本文目錄一覽:
- 1、python異步協程跟多進程多線程哪個效率高?
- 2、協程與異步IO
- 3、python為什麼引入協程
- 4、python協程(4):asyncio
- 5、python協程為什麼不需要枷鎖
- 6、簡述python進程,線程和協程的區別及應用場景
python異步協程跟多進程多線程哪個效率高?
線程是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。
一個程序的執行實例就是一個進程。每一個進程提供執行程序所需的所有資源。
PS:上面都是摘抄自網頁鏈接這裡的,具體的可以看看這裡,你的答案在圖片的最後一點。因為線程和進程是不能層面的定義,一個進程可以包括多個線程,所以沒有可比性~
協程與異步IO
協程,又稱微線程,纖程。英文名 Coroutine 。Python對協程的支持是通過 generator 實現的。在generator中,我們不但可以通過for循環來迭代,還可以不斷調用 next()函數 獲取由 yield 語句返回的下一個值。但是Python的yield不但可以返回一個值,它還可以接收調用者發出的參數。yield其實是終端當前的函數,返回給調用方。python3中使用yield來實現range,節省內存,提高性能,懶加載的模式。
asyncio是Python 3.4 版本引入的 標準庫 ,直接內置了對異步IO的支持。
從Python 3.5 開始引入了新的語法 async 和 await ,用來簡化yield的語法:
import asyncio
import threading
async def compute(x, y):
print(“Compute %s + %s …” % (x, y))
print(threading.current_thread().name)
await asyncio.sleep(x + y)
return x + y
async def print_sum(x, y):
result = await compute(x, y)
print(“%s + %s = %s” % (x, y, result))
print(threading.current_thread().name)
if __name__ == “__main__”:
loop = asyncio.get_event_loop()
tasks = [print_sum(1, 2), print_sum(3, 4)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
線程是內核進行搶佔式的調度的,這樣就確保了每個線程都有執行的機會。而 coroutine 運行在同一個線程中,由語言的運行時中的 EventLoop(事件循環) 來進行調度。和大多數語言一樣,在 Python 中,協程的調度是非搶佔式的,也就是說一個協程必須主動讓出執行機會,其他協程才有機會運行。
讓出執行的關鍵字就是 await。也就是說一個協程如果阻塞了,持續不讓出 CPU,那麼整個線程就卡住了,沒有任何並發。
PS: 作為服務端,event loop最核心的就是IO多路復用技術,所有來自客戶端的請求都由IO多路復用函數來處理;作為客戶端,event loop的核心在於利用Future對象延遲執行,並使用send函數激發協程,掛起,等待服務端處理完成返回後再調用CallBack函數繼續下面的流程
Go語言的協程是 語言本身特性 ,erlang和golang都是採用了CSP(Communicating Sequential Processes)模式(Python中的協程是eventloop模型),但是erlang是基於進程的消息通信,go是基於goroutine和channel的通信。
Python和Go都引入了消息調度系統模型,來避免鎖的影響和進程/線程開銷大的問題。
協程從本質上來說是一種用戶態的線程,不需要系統來執行搶佔式調度,而是在語言層面實現線程的調度 。因為協程 不再使用共享內存/數據 ,而是使用 通信 來共享內存/鎖,因為在一個超級大系統里具有無數的鎖,共享變量等等會使得整個系統變得無比的臃腫,而通過消息機制來交流,可以使得每個並發的單元都成為一個獨立的個體,擁有自己的變量,單元之間變量並不共享,對於單元的輸入輸出只有消息。開發者只需要關心在一個並發單元的輸入與輸出的影響,而不需要再考慮類似於修改共享內存/數據對其它程序的影響。
python為什麼引入協程
python的多線程是偽的,因為python有GIL(全局解釋器鎖,這個你不知道可以自己 百度),同一個cpu只能同時執行一個任務,多線程同一時刻只有拿到GIL的線程在執行。而協程也是並發執行多個任務,但是是在程序員的控制下按序執行,比起線程,協程可控性要強,效率跟線程差不多,所以引入了協程來替代大多數情況下的線程。
python協程(4):asyncio
asyncio是官方提供的協程的類庫,從python3.4開始支持該模塊
async awiat是python3.5中引入的關鍵字,使用async關鍵字可以將一個函數定義為協程函數,使用awiat關鍵字可以在遇到IO的時候掛起當前協程(也就是任務),去執行其他協程。
await + 可等待的對象(協程對象、Future對象、Task對象 – IO等待)
注意:在python3.4中是通過asyncio裝飾器定義協程,在python3.8中已經移除了asyncio裝飾器。
事件循環,可以把他當做是一個while循環,這個while循環在周期性的運行並執行一些協程(任務),在特定條件下終止循環。
loop = asyncio.get_event_loop():生成一個事件循環
loop.run_until_complete(任務):將任務放到事件循環
Tasks用於並發調度協程,通過asyncio.create_task(協程對象)的方式創建Task對象,這樣可以讓協程加入事件循環中等待被調度執行。除了使用 asyncio.create_task() 函數以外,還可以用低層級的 loop.create_task() 或 ensure_future() 函數。不建議手動實例化 Task 對象。
本質上是將協程對象封裝成task對象,並將協程立即加入事件循環,同時追蹤協程的狀態。
注意:asyncio.create_task() 函數在 Python 3.7 中被加入。在 Python 3.7 之前,可以改用 asyncio.ensure_future() 函數。
下面結合async awiat、事件循環和Task看一個示例
示例一:
*注意:python 3.7以後增加了asyncio.run(協程對象),效果等同於loop = asyncio.get_event_loop(),loop.run_until_complete(協程對象) *
示例二:
注意:asyncio.wait 源碼內部會對列表中的每個協程執行ensure_future從而封裝為Task對象,所以在和wait配合使用時task_list的值為[func(),func()] 也是可以的。
示例三:
python協程為什麼不需要枷鎖
Python是一門動態的腳本語言,它有一個鎖叫做全局解釋器鎖,它這個鎖是加在cpython解釋器上的,我們說的Python多線程,再線程切換的時候加了鎖,用了控制同步。所以多線程不是真正意義的並發,而協程是在線程裡面的,線程並沒有鎖,一個線程可以有多個協程,協程又叫微線程,它的切換完全由自己創建,它有幾種實現方式,一種是yield和send,一種是gevent,一種是greenlet,線程的並發不好,協程可以有上萬次並發。回到之前的問題,因為協程在線程內,而線程本身沒有鎖,所以攜程沒有鎖。
簡述python進程,線程和協程的區別及應用場景
協程多與線程進行比較
1) 一個線程可以多個協程,一個進程也可以單獨擁有多個協程,這樣python中則能使用多核CPU。
2) 線程進程都是同步機制,而協程則是異步
3) 協程能保留上一次調用時的狀態,每次過程重入時,就相當於進入上一次調用的狀態
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/207025.html