繼續談談Twisted

2021-09-23 16:10:57 字數 3434 閱讀 5964

那我就來繼續隨便談談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

sock = socket.socket(socket.af_inet, socket.sock_stream)

sock.connect((ip, port))

sock.send('hello world1')

time.sleep(3)

sock.send('hello world2')

time.sleep(3)

sock.send('hello world3')

sock.close()

先來看看socket的server, 顯然這段**只能接收到第一條message

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

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

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

sock = socket.socket(socket.af_inet, socket.sock_stream)

sock.setsockopt(socket.sol_socket, socket.so_reuseaddr, 1)

sock.bind(('localhost', 3000))

sock.listen(5)

while true:

conn, addr = sock.accept()

buf = conn.recv(1024)

print 'recv data:' + buf + '\n'

再來看看用twisted實現的server, 可以試試同時開啟多個上面的client, 該server是可以同時併發接收每個client的資料的, 而不是需要處理完乙個client, 才開始處理下乙個. 所以確實用twisted開發server比直接使用socket方便合理許多.

from twisted.internet import protocol, reactor

from twisted.internet.protocol import factory

class echo(protocol.protocol):

def connectionmade(self):

self.factory.numprotocols = self.factory.numprotocols+1

print 'connectionmade'

print 'numprotocols:'+ str(self.factory.numprotocols)

def connectionlost(self, reason):

self.factory.numprotocols = self.factory.numprotocols-1

print 'connectionlost'

print 'numprotocols:'+ str(self.factory.numprotocols)

def datareceived(self, data):

#self.transport.write(data)

print 'datareceived:' + str(data)

myfactory = factory()

myfactory.protocol = echo

myfactory.numprotocols = 0

reactor.listentcp(3000, myfactory)

reactor.run()

想想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加到偵聽佇列中.

繼續談談Twisted

那我就來繼續隨便談談twisted 首先討論一下,為什麼需要twisted,需要非同步 為了更高效的利用cpu和資源,提高使用者的相應速度 任務需要較長時間才能完成分成兩種情況,1 計算量較大,需要cpu算好久才能算出來,自然算出來才能給結果,稱為cpu等待.2 需要等待其他的資料,比如需要從伺服器...

Twisted基本模型

twisted 網路程式設計框架是一種基於事件的網路程式設計框架,使用者需要繼承特定的類,並過載其中的方法來處理網路通訊 中可能出現的各種情況。twisted的網路通訊模型 最基本的也要由三部分組成 反應器 reactor 協議 protocol 工廠 factory 1 其中反應器reactor用...

Twisted基本模型

一 twisted基本模型 twisted 網路程式設計框架是一種基於事件的網路程式設計框架,使用者需要繼承特定的類,並過載其中的方法來處理網路通訊 中可能出現的各種情況。twisted的網路通訊模型 最基本的也要由三部分組成 反應器 reactor 協議 protocol 工廠 factory 1...