日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

msdn windows server 按电源事件api_【tornado源码分析】I/O事件循环机制与多进程

發布時間:2024/1/23 windows 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 msdn windows server 按电源事件api_【tornado源码分析】I/O事件循环机制与多进程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

tornado是一個異步非阻塞的web框架,由Facebook開源,源代碼用的python語言。之前也用tornado做過幾個項目,實習的時候公司也是用的tornado來做工業物聯網的后端。空余時間研究一下tornado的源碼,畢竟是Facebook的代碼,還是有學習的價值。以下為學習的一點筆記。


一.socket編程

現代計算機網絡中使用TCP/IP協議架構:物理鏈路層,ip層,TCP/UDP層,應用層。

socket層則是對TCP/UDP層的一層簡要封裝,能夠方便開發者定義自己的高層應用協議。在python中,使用內置的socket模塊能夠進行socket編程。該模塊提供的api有:

利用提供的這些基礎api,能夠很方便的自行編寫高層協議,比如,你可以自己實現一個HTTP server。 HTTP協議基于TCP協議,是面向連接的,構造一條虛電路,保證數據包的順序,不丟包,可靠的發送。基于TCP的socket邏輯架構如下:

socket在類unix系統中均可以看成是一個特殊文件,

sock=socket.socket()

返回一個句柄sock,sock.fileno()即為該句柄的編號,為int類型。考慮一下在tornado中tcpserver如何在ioloop注冊事件。在ioloop中提供了一個方法:

def add_handler( # noqa: F811self, fd: Union[int, _Selectable], handler: Callable[..., None], events: int) -> None

add_handler函數用來綁定socket對應的回調函數,具體來說:當服務器端socket對應的’讀事件‘(IOOP.READ,即為參數event)被觸發時,將調用handler函數進行處理。以上理解比較抽象,下面寫個例子,理解下:

首先寫個server:

from tornado import httpserver, ioloop, tcpserver import socketdef a(A, B):print("====開始測試=====")print(A)print(B)print("我是服務器socket的回調函數")if __name__ == '__main__':loop = ioloop.IOLoop.current()server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server.bind(('127.0.0.1', 8881))loop.add_handler(server.fileno(), a, ioloop.IOLoop.READ)server.listen()#conn, addr = server.accept()#a = conn.recv(1024)#print("服務器收到的數據", repr(a))#loop.spawn_callback(c, conn)loop.start()

以上server用socket編程來實現,功能為:首先定義一個socket,變量名為server,該socket綁定在8881端口上。然后我們利用add_handler函數將該socket注冊到ioloop上,注冊的這一步在平時的開發中的寫法為:

server = TCPServer()server.bind(8881)server.start(0) # Forks multiple sub-processesIOLoop.current().start()

在注冊該socket之后,ioloop.start()開始事件循環。

再寫一個client:

import socketsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('127.0.0.1', 8881)) sock.sendall(b"hello,worldfwefewfwefwefwefwefwefwefw") print(sock.fileno()) # a = sock.recv(1024) # print(repr(a)) sock.close()

該client,依然是創建一個socket,然后請求連接8881端口的服務(模擬發送HTTP請求)。當該數據被發送之后,可以看見server端的輸出為:

可以看見ioloop監聽到了client對server發送的請求,進行了回調。具體來說:client向server發送了一個請求,server端的socket在收到該請求后,會觸發READ事件,此時ioloop會觸發該socket對應的回調函數。


二.tornado中的多進程

對于tornado這種單線程的web框架,如果遇到cpu bound類型的任務,雖然及時能夠通過coroutine模式保證不會丟失服務,但是由于CPU被占用,所以響應時間一點也不會減少。此時可以考慮使用多進程tornado,或者多tornado實例,然后再用nginx做負載均衡(這個還沒試過)。

我們通過time.sleep(20)來模擬CPU的計算過程,原因是在這20s內,server不能響應其他用戶的請求(cpu一直在計算)。

代碼如下:

class MainHandler(tornado.web.RequestHandler):async def get(self):print("睡眠10s")time.sleep(20)print("pid", os.getpid())print("睡眠結束")self.write(str(os.getpid()))class WebHandler(tornado.web.RequestHandler):async def get(self):print("hello,world123")def make_app():return tornado.web.Application([tornado.web.url(r"/123", MainHandler, name="hello"),tornado.web.url(r"/456", WebHandler, name="web"),]) if __name__ == "__main__":app = make_app()# server = tornado.httpserver.HTTPServer(app)# server.bind(8888, '127.0.0.1')# server.start(0)sockets = tornado.netutil.bind_sockets(8888)tornado.process.fork_processes(2)server = tornado.httpserver.HTTPServer(app)server.add_sockets(sockets)loop1 = tornado.ioloop.IOLoop()loop = loop1.current()# loop.add_handler(1, a, 0x001)# loop.add_handler(2, b, 0x004)# loop.add_callback(d)# print(loop1._ioloop_for_asyncio)loop.start()由于我的機器有四個核,所以輸出如下:

在tornado中,多進程是通過os.fork函數來實現(windows無法實現)。父進程在fork子進程之后,子進程會和父進程同時執行剩下的代碼,需要注意os.fork有兩個返回值,如果返回值為0,則表明當前這個進程是子進程,如果返回值為int,則int是子進程的pid號。那么通過這種方式在執行cpubound的任務時,可以充分利用多核。在tornado中的內部實現為tornado.netutil.add_accept_handler函數:

def add_accept_handler(sock: socket.socket, callback: Callable[[socket.socket, Any], None] ) -> Callable[[], None]:io_loop = IOLoop.current()removed = [False]def accept_handler(fd: socket.socket, events: int) -> None:for i in range(_DEFAULT_BACKLOG):if removed[0]:# The socket was probably closedreturntry:connection, address = sock.accept()except socket.error as e:if errno_from_exception(e) in _ERRNO_WOULDBLOCK:returnif errno_from_exception(e) == errno.ECONNABORTED:continueraiseset_close_exec(connection.fileno())callback(connection, address)def remove_handler() -> None:io_loop.remove_handler(sock)removed[0] = Trueio_loop.add_handler(sock, accept_handler, IOLoop.READ)return remove_handler

關鍵在于內部函數accept_handler,當使用多進程時會產生驚群效應,那么tornado是如何防止這種情況的呢?關鍵在:

if errno_from_exception(e) in _ERRNO_WOULDBLOCK:

在異步函數中(errno.EWOULDBLOCK,errno.EAGAIN)可以不被當做錯誤,用來避免客戶端的socket被重復處理。


歡迎關注微信公眾號:生物信息與python,及時更新與分享~

超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

總結

以上是生活随笔為你收集整理的msdn windows server 按电源事件api_【tornado源码分析】I/O事件循环机制与多进程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。