天天看點

繼續談談Twisted

那我就來繼續随便談談twisted

首先讨論一下, 為什麼需要twisted, 需要異步

為了更高效的利用cpu和資源, 提高使用者的相應速度

任務需要較長時間才能完成分成兩種情況,

1) 計算量較大, 需要cpu算好久才能算出來, 自然算出來才能給結果, 稱為cpu等待.

2) 需要等待其他的資料, 比如需要從伺服器等待擷取資訊, 需要從資料庫等待查詢結果, 這種雖然自己很閑, 無事可做, 但不得不幹等, 稱為i/o等待.

cpu等待是沒辦法的, 就是要算那麼長時間, 唯一能做的是為了讓使用者體驗好些, 大家輪流占用cpu, 這種典型的方法就是多線程...

i/o等待是應該需要優化的, 這是幹等白白浪費并占住了資源, 使得其他使用者也無法使用. 這兒就需要異步, 需要twisted, 需要callback.

本來我要等待資料, 然後程式才能繼續, 異步的做法是, 把後續的處理程式封裝成callback, errback, 把等待資料ready封裝成event (讓系統調用select去偵聽資料i/o). 這樣主程式不需要去專門等待某一個event, 有event觸發就處理, 這就達到異步的效果.

是以在判斷是否需要使用異步, 該不該使用twisted時, 隻需要考慮是否存在i/o等待, 隻要有i/o等待就應該考慮使用異步.

而twisted的代碼無論多麼複雜, 其實都是在做如下這樣簡單的事情,

通過定義protocal和factory來解析請求

通過定義callback來處理請求

定義i/o connection (将factory作為參數, 包含protocal和callback), 并加到event loop(reactor)中去

run reactor

再來, twisted主要應用于什麼場景, 使用twisted真的比直接使用socket友善合理嗎

twisted主要用于開發server, 它就是為此而生的

下面我們通過簡單的例子來和socket對比一下,

下面我們先來看一下用戶端, 建立一個連結, 發送多條message

先來看看socket的server, 顯然這段代碼隻能接收到第一條message

如果需要接受所有的message, 必須在conn.recv前加上while, 這樣保證接收到所有message後才去accept新的connection.

如果同時打開多個client, 那麼這兒必須先接收完第一個client的所有message, 才能開始接收第二個client的...

這樣就block了, 使用者就不爽了...

再來看看用twisted實作的server, 可以試試同時打開多個上面的client, 該server是可以同時并發接收每個client的資料的, 而不是需要處理完一個client, 才開始處理下一個. 是以确實用twisted開發server比直接使用socket友善合理許多.

想想twisted是怎麼樣實作這種異步的, 是怎麼樣儲存各個connection并在之間自由切換的?

從頭開始, 大家先簡單把i/o想象成檔案, 對于作業系統而言, i/o操作就等同于對檔案的讀寫操作, 其他對系統是透明的.

對于一個twisted server, 剛開始監聽一個i/o端口(這兒可以想象對于twisted有個偵聽隊列, 剛開始list中隻有一個port), 等待請求...

請求到達(相當于conn, addr = sock.accept() ), 觸發connectionmade event, 并把該connection加到偵聽隊列.

某connection收到資料, 觸發datareceived event

某connection closed, 觸發connectionlost event, 并把該connection從偵聽隊列中删除.

如果在某個callback, 如datareceived中出現一個很耗時的任務時該怎麼辦, 比如需要從另外一個伺服器擷取資料.

異步中, callback使用的第一原則是, 不能block, 因為主線程一旦block, 啥事就都做不了

是以這兒必須要再次使用異步, 在callback中再次設定event和callback, 并将和遠端伺服器的connection加到偵聽隊列中.

本文章摘自部落格園,原文釋出日期:2011-11-12