協程不是系統級執行緒,很多時候協程被稱為“輕量級執行緒”、“微執行緒”、“纖程(fiber)”等。簡單來說可以認為協程是執行緒裡不同的函式,這些函式之間可以相互快速切換。
協程和使用者態執行緒非常接近,使用者態執行緒之間的切換不需要陷入核心,但部分作業系統中使用者態執行緒的切換需要核心態執行緒的輔助。
協程是程式語言(或者 lib)提供的特性(協程之間的切換方式與過程可以由程式設計人員確定),是使用者態操作。協程適用於 IO 密集型的任務。常見提供原生協程支援的語言有:c++20、golang、python 等,其他語言以庫的形式提供協程功能,比如 C++20 之前騰訊的 fiber 和 libco 等等。
2.1 介紹
asyncio 是用來編寫併發程式碼的庫,使用 async/await 語法。
asynci0 被用作多個提供高效能 Python 非同步框架的基礎,包括網路和網站服務,資料庫連線庫,分散式任務佇列等等,asyncio 往往是構建 10 密集型和高層級 結構化 網路程式碼的最佳選擇。
asyncio 提供一組高層級 API用於:
·併發地執行 Python 協程 並對其執行過程實現完全控制:
·執行網路 10 和 IPC:
。控制子程序:
。透過佇列實現分散式任務;
·同步併發程式碼;
·建立和管理事件迴圈,以提供非同步 API用於 網路化,執行 子程序,處理 OS 訊號 等等
使用 transports 實現高效率協議:
·透過 async/await 語法橋接基於回撥的庫和程式碼。
1)協程透過 async/await 語法進行宣告,是編寫 asyncio 應用的推薦方式。
asyncio.run() 函式用來執行最高層級的入口點"main()"函式。
asyncio.sleep(delay,result=None,,loop=None) 函式用來阻塞指定的秒數。
2)事件迴圈函式(包括迴圈的建立、執行和停止)
asyncio.get _running_loop() 函式返回當前 OS 執行緒中正在執行的事件迴圈。
asyncio.get event loop()函式獲取當前事件迴圈。
asyncio.set event loop(loop) 函式將 loop 設定為當前 OS 執行緒的當前事件迴圈。
asyncio.new_event loop() 函式建立一個新的事件迴圈。
loop.run until complete(future) 函式執行直到 future (Future 的例項) 被完成。
loop.run forever()函式執行事件迴圈直到 stop() 被呼叫。
loop.stop()函式停止事件迴圈。
loop.is_running() 函式返回 True 如果事件迴圈當前正在執行loop.is closed()函式如果事件迴圈已經被關閉,返回 True 。loop.close() 函式關閉事件迴圈。
loop.create future()函式建立一個附加到事件迴圈中的 asyncio.Future 物件。loop.create task(coro,,name=None)函式安排一個 協程 的執行。返回一個 Task 物件,loop.set task factory(factory) 函式設定一個 task 工廠,被用於 loop.create task()。loop.get task factory()函式返回一個任務工廠,或者如果是使用預設值則返回 None。
3)排程回撥和延遲迴調
loop.call soon(callback,args,context=None)函式安排 calback 在事件迴圈的下一次迭代時附帶 args 引數被呼叫。回撥按其註冊順序被呼叫。每個回撥僅被呼叫一次。方法不是執行緒安全的。loop.call soon threadsafe(calback,args,context=None)函式是 call soon() 的執行緒安全變體。必須被用於安排 來自其他執行緒 的口調。
loop.call later(delay, callback,args, context=None) 函式安排 callback 在給定的 delay 秒(可以是 int 或者 float)後被呼叫。loop.call at(when, calback,args,context=None)函式安排 calback 在給定的絕對時間戳的時間(一個int 或者 foat)被呼叫,使用與 loop.time()同樣的時間參考。
loop.time() 函式根據時間迴圈內部的單調時鐘,返回當前時間, float 值。
socket連線和Streams函式
loop.create connection(protocol factory, host=None, port=None, , ssl=None, family=0, proto=0, flags=0, sock=None,local addr=None, server hostname=None, ssl handshake timeout=None, happy, eyeballs delay=None, interleave=None)函式開啟一個流式傳輸連線,連線到由 host 和 port 指定的地址。
loop.create serverlprotocol factory, hostNone, port=None,, familv=socket.AF UNSPEc, flags=socke.Al PASSIVEsock=None, backlog=100,ssl=None, reuse address=None,reuse portNone,ssl handshake timeout=None.start serving=True)函式建立TCP服務 (socket 型別 SOCK STREAM)監聽 host 地址的 port 埠。
loop.create unix server(protocol factory, path=None,, sock=None, backlog=100, ssl=None.ssl handshake timeouteNone, start serving=True) 函式與loop.create server)類似但是專用於 AF UNIX套接字族。path 是必要的 Unix 域套接字名稱,除非提供了 sock 引數。 抽象的 Unix 套接字,str, bvtes 和 Path 路徑都是受支援的。
loop.connect accepted socketlprotocol factory, sock,sslNone,ssl handshake timeout=None) 函式將已被接受的連線包裝成一個傳輸/協議對。
loop.sock recv(sock,nbytes)函式從 sock 接收至多 nbytes。 socket.recv() 的非同步版本。loop.sock recv into(sock,buf) 函式從 sock 接收資料放入 buf 緩衝區。模仿了陽塞型的 socket.recv into() 方法。loop.sock sendall(sock, data) 函式將 data 傳送到 sock 套接字。 socket.sendal() 的非同步版本。
loop.sock accept(sock)函式接受一個連線。 模仿了阻塞型的 socket.accept() 方法。loop.sock sendfile(sock,file, ofset=0,count=None,,fallback=True) 函式在可能的情況下使用高效能的 os.sendfile 傳送檔案。返回所傳送的位元組總數。
asyncio.open connection(host=None, port=None, , loop=None, limit=None, ssl=None, family=0, proto=0, flags=0sock=None, local addreNone, server hostname=None,ssl handshake timeout=None) 函式建立網路連線並返回一對(reader. writer)物件。
asyncio.start serverlclient connected cb, host=None, port=None., loop=None, limitNone, familv=socket.AF UNSPECflags=socketAl PASSIVE, sock=None, backlog=100,ssl=None, reuse address=None, reuse port=None.ssl handshake timeout=None,start serving=True) 函式啟動套接字服務。
asyncio.open unix connection(path=None, , loop=None, limit=None, sslNone, sockeNone, server hostname=None.ssl handshake timeout=None)函式建立一個 Unix套接字連線並返回(reader, writer)這對返回值。與open connection() 相似但是操作在 Unix 套接字上。
asyncio.start unix serverlclient connected cb, path=None, , loop=None, limit=None, sock=None, backlog=100ssl=None, ssl handshake timeout=None, start serving=True)函式啟動-個Unix socket服務,與 start server) 相似,但是是在 Unix 套接字上的操作。
asyncio.$treamReader 這個類表示一個提供api來從I0流中讀取資料的讀取器物件。
reader.read(n=-1)函式讀取 n個byte.如果沒有設定n,則自動置為 -1讀至 EOF 並返回所有讀取的byte。reader.readline() 函式讀取一行,其中“行"指的是以" 結尾的位元組序列。如果讀到EOF而沒有找到i ,該方法返回部分讀取的資料。如果讀到EOF,且內部緩衝區為空,則返回一個空的 bytes 物件。reader.readexactly(n)函式精準讀取 n個 bytes,不能超過也不能少於reader.readuntilseparatoreb'n”函式從流中讀取資料直至遇到 分隔符成功後,資料和指定的separator將從內部緩衝區中刪除(或者說被消費掉)。返回的資料將包括在未尾的指定separator。如果讀取的資料量超過了配置的流限制,將引發 LimitOverunError 異常,資料將留在內部緩衝區中並可以再次讀取。如果在找到完整的separator之前到達EOF,則會引發 IncompleteReadEror 異常,並重置內部緩衝區。 IncompleteReadError.partial屬性可能包含指定separator的一部分。reader.at eofl) 函式如果緩衝區為空並且 feed eof() 被呼叫,則返回 True 。
asyncio.$treamWriter 這個類表示一個寫入器物件,該物件提供api以便於寫資料至I0流中
writer,write(data)函式會嘗試立即將 data 寫入到下層的套接字。 如果寫入失敗,資料會被排入內部寫緩衝佇列直到可以被髮送。writer.writelines(data)函式會立即嘗試將一個位元組串列表(或任何可迭代物件)寫入到下層的套接字。如果寫入失敗,資料會被排入內部寫緩衝佇列直到可以被髮送。
writer.close()函式會關閉流以及下層的套接字,
writer.can write eofl) 函式如果下層的傳輸支援 write eof() 方法則返回“True”,否則返回 False.
writer.write eof()函式在已緩衝的寫入資料被重新整理後關閉流的寫入端。
writer.transport()函式返回下層的 asyncio 傳輸。
writer.drain() 函式等待直到可以適當地恢復寫入到流
writer.is closing()函式如果流已被關閉或正在被關閉則返回 True。
writer.wait closed()函式等待直到流被關閉。
8)Future
asyncio.Future(,loop=None)函式是一個 Future 代表一個非同步運算的最終結果。執行緒不安全。asyncio.isfuture(obj)函式用來判斷如果 obj為一個 asyncio.Future類的示例、 asyncio.Task 類的例項或者一個具有 asyncio future blocking 屬性的物件,返回 True。asyncio.ensure future(obj,,loop=None)函式建立新任務。asyncio.wrap futurelfuture.,loop=None)函式將-個 concurrent.futures.Future 物件封裝到 asvncio.Future 物件中
Future 物件相關函式:
fut.result() 函式返回 Future 的結果。
fut.set result(result) 函式將 Future 標記為 完成 並設定結果。fut.set exception(exception)函式將 Future 標記為 完成 並設定一個異常。fut.done() 函式如果 Future 為已 完成 則返回 True 。fut.cancelled() 函式是如果 Future 已取消則返回 Truefut.add done callback(callback,*,context=None) 函式新增一個在 Future 完成 時執行的回撥函式。fut.remove done callback(callback) 函式從回撥列表中移除 callback。fut.cancel() 函式取消 Future 並排程回撥函式。
fut.exception() 函式返回 Future 已設定的異常,
fut.get loop() 函式返回 Future 物件已繫結的事件迴圈。