摘要:項(xiàng)目地址我之前翻譯了協(xié)程原理這篇文章之后嘗試用了模式下的協(xié)程進(jìn)行異步開發(fā),確實(shí)感受到協(xié)程所帶來的好處至少是語法上的。
項(xiàng)目地址:https://git.io/pytips
我之前翻譯了Python 3.5 協(xié)程原理這篇文章之后嘗試用了 Tornado + Motor 模式下的協(xié)程進(jìn)行異步開發(fā),確實(shí)感受到協(xié)程所帶來的好處(至少是語法上的:D)。至于協(xié)程的 async/await 語法是如何由開始的 yield 生成器一步一步上位至 Python 的 async/await 組合語句,前面那篇翻譯的文章里面講得已經(jīng)非常詳盡了。我們知道協(xié)程的本質(zhì)上是:
allowing multiple entry points for suspending and resuming execution at certain locations.
允許多個(gè)入口對(duì)程序進(jìn)行掛起、繼續(xù)執(zhí)行等操作,我們首先想到的自然也是生成器:
def jump_range(upper): index = 0 while index < upper: jump = yield index if jump is None: jump = 1 index += jump jump = jump_range(5) print(jump) print(jump.send(None)) print(jump.send(3)) print(jump.send(None))
0 3 4
后來又新增了 yield from 語法,可以將生成器串聯(lián)起來:
def wait_index(i): # processing i... return (yield i) def jump_range(upper): index = 0 while index < upper: jump = yield from wait_index(index) if jump is None: jump = 1 index += jump jump = jump_range(5) print(jump) print(jump.send(None)) print(jump.send(3)) print(jump.send(None))
0 3 4
yield from/send 似乎已經(jīng)滿足了協(xié)程所定義的需求,最初也確實(shí)是用 @types.coroutine 修飾器將生成器轉(zhuǎn)換成協(xié)程來使用,在 Python 3.5 之后則以專用的 async/await 取代了 @types.coroutine/yield from:
class Wait(object): """ 由于 Coroutine 協(xié)議規(guī)定 await 后只能跟 awaitable 對(duì)象, 而 awaitable 對(duì)象必須是實(shí)現(xiàn)了 __await__ 方法且返回迭代器 或者也是一個(gè)協(xié)程對(duì)象, 因此這里臨時(shí)實(shí)現(xiàn)一個(gè) awaitable 對(duì)象。 """ def __init__(self, index): self.index = index def __await__(self): return (yield self.index) async def jump_range(upper): index = 0 while index < upper: jump = await Wait(index) if jump is None: jump = 1 index += jump jump = jump_range(5) print(jump) print(jump.send(None)) print(jump.send(3)) print(jump.send(None))
0 3 4
與線程相比
協(xié)程的執(zhí)行過程如下所示:
import asyncio import time import types @types.coroutine def _sum(x, y): print("Compute {} + {}...".format(x, y)) yield time.sleep(2.0) return x+y @types.coroutine def compute_sum(x, y): result = yield from _sum(x, y) print("{} + {} = {}".format(x, y, result)) loop = asyncio.get_event_loop() loop.run_until_complete(compute_sum(0,0))
Compute 0 + 0... 0 + 0 = 0
這張圖(來自: PyDocs: 18.5.3. Tasks and coroutines)清楚地描繪了由事件循環(huán)調(diào)度的協(xié)程的執(zhí)行過程,上面的例子中事件循環(huán)的隊(duì)列里只有一個(gè)協(xié)程,如果要與上一部分中線程實(shí)現(xiàn)的并發(fā)的例子相比較,只要向事件循環(huán)的任務(wù)隊(duì)列中添加協(xié)程即可:
import asyncio import time # 上面的例子為了從生成器過度,下面全部改用 async/await 語法 async def _sum(x, y): print("Compute {} + {}...".format(x, y)) await asyncio.sleep(2.0) return x+y async def compute_sum(x, y): result = await _sum(x, y) print("{} + {} = {}".format(x, y, result)) start = time.time() loop = asyncio.get_event_loop() tasks = [ asyncio.ensure_future(compute_sum(0, 0)), asyncio.ensure_future(compute_sum(1, 1)), asyncio.ensure_future(compute_sum(2, 2)), ] loop.run_until_complete(asyncio.wait(tasks)) loop.close() print("Total elapsed time {}".format(time.time() - start))
Compute 0 + 0... Compute 1 + 1... Compute 2 + 2... 0 + 0 = 0 1 + 1 = 2 2 + 2 = 4 Total elapsed time 2.0042951107025146總結(jié)
這兩篇主要關(guān)于 Python 中的線程與協(xié)程的一些基本原理與用法,為此我搜索了不少參考文章與鏈接,對(duì)我自己理解它們的原理與應(yīng)用場景也有很大的幫助(當(dāng)然也有可能存在理解不到位的地方,歡迎指正)。當(dāng)然在這里還是主要關(guān)注基于 Python 的語法與應(yīng)用,如果想要了解更多底層實(shí)現(xiàn)的細(xì)節(jié),可能需要從系統(tǒng)調(diào)度等底層技術(shù)細(xì)節(jié)開始學(xué)習(xí)(幾年前我記得翻閱過《深入理解LINUX內(nèi)核》這本書,雖然大部分細(xì)節(jié)已經(jīng)記不清楚了,但對(duì)于理解其它人的分析、總結(jié)還是有一定幫助的)。這里討論的基于協(xié)程的異步主要是借助于事件循環(huán)(由asyncio標(biāo)準(zhǔn)庫提供),包括上文中的示意圖,看起來很容易讓人聯(lián)想到 Node.js 的事件循環(huán) & 回調(diào),但是協(xié)程與回調(diào)也還是有區(qū)別的,具體就不在這里展開了,可以參考下面第一條參考鏈接。
歡迎關(guān)注公眾號(hào) PyHub 每日推送
參考Python 中的進(jìn)程、線程、協(xié)程、同步、異步、回調(diào)
我是一個(gè)線程
Concurrency is not Parallelism
A Curious Course on Coroutines and Concurrency
PyDocs: 17.1. threading — Thread-based parallelism
PyDocs: 18.5.3. Tasks and coroutines
[譯] Python 3.5 協(xié)程究竟是個(gè)啥
協(xié)程的好處是什么? - crazybie 的回答
Py3-cookbook:第十二章:并發(fā)編程
Quora: What are the differences between parallel, concurrent and asynchronous programming?
Real-time apps with gevent-socketio
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/37866.html
摘要:中關(guān)于線程的標(biāo)準(zhǔn)庫是,之前在版本中的在之后更名為,無論是還是都應(yīng)該盡量避免使用較為底層的而應(yīng)該使用。而與線程相比,協(xié)程尤其是結(jié)合事件循環(huán)無論在編程模型還是語法上,看起來都是非常友好的單線程同步過程。 項(xiàng)目地址:https://git.io/pytips 要說到線程(Thread)與協(xié)程(Coroutine)似乎總是需要從并行(Parallelism)與并發(fā)(Concurrency)談起...
摘要:所以與多線程相比,線程的數(shù)量越多,協(xié)程性能的優(yōu)勢越明顯。值得一提的是,在此過程中,只有一個(gè)線程在執(zhí)行,因此這與多線程的概念是不一樣的。 真正有知識(shí)的人的成長過程,就像麥穗的成長過程:麥穗空的時(shí)候,麥子長得很快,麥穗驕傲地高高昂起,但是,麥穗成熟飽滿時(shí),它們開始謙虛,垂下麥芒。 ——蒙田《蒙田隨筆全集》 上篇論述了關(guān)于python多線程是否是雞肋的問題,得到了一些網(wǎng)友的認(rèn)可,當(dāng)然也有...
摘要:上一篇文章第二章實(shí)戰(zhàn)演練開發(fā)網(wǎng)站第五節(jié)輸出相應(yīng)函數(shù)下一篇文章第二章實(shí)戰(zhàn)演練開發(fā)網(wǎng)站第七節(jié)安全機(jī)制有兩種方式可改變同步的處理流程異步化針對(duì)的處理函數(shù)使用修飾器,將默認(rèn)的同步機(jī)制改為異步機(jī)制。使用異步對(duì)象處理耗時(shí)操作,比如本例的。 上一篇文章:Python:Tornado 第二章:實(shí)戰(zhàn)演練:開發(fā)Tornado網(wǎng)站:第五節(jié):RequestHandler:輸出相應(yīng)函數(shù)下一篇文章:Python:...
摘要:事件循環(huán)是異步編程的底層基石。對(duì)事件集合進(jìn)行輪詢,調(diào)用回調(diào)函數(shù)等一輪事件循環(huán)結(jié)束,循環(huán)往復(fù)。協(xié)程直接利用代碼的執(zhí)行位置來表示狀態(tài),而回調(diào)則是維護(hù)了一堆數(shù)據(jù)結(jié)構(gòu)來處理狀態(tài)。時(shí)代的協(xié)程技術(shù)主要是,另一個(gè)比較小眾。 Coding Crush Python開發(fā)工程師 主要負(fù)責(zé)豈安科技業(yè)務(wù)風(fēng)險(xiǎn)情報(bào)系統(tǒng)redq。 引言 1.1. 存儲(chǔ)器山 存儲(chǔ)器山是 Randal Bryant 在《深入...
摘要:并發(fā)用于制定方案,用來解決可能但未必并行的問題。在協(xié)程中使用需要注意兩點(diǎn)使用鏈接的多個(gè)協(xié)程最終必須由不是協(xié)程的調(diào)用方驅(qū)動(dòng),調(diào)用方顯式或隱式在最外層委派生成器上調(diào)用函數(shù)或方法。對(duì)象可以取消取消后會(huì)在協(xié)程當(dāng)前暫停的處拋出異常。 導(dǎo)語:本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之控制流程篇的重點(diǎn)知識(shí)及個(gè)人心得,打算入門Python的朋友們可以來一起學(xué)習(xí)并交流。 本文重點(diǎn): 1、了解asyncio...
閱讀 1389·2021-09-22 10:02
閱讀 1901·2021-09-08 09:35
閱讀 4061·2021-08-12 13:29
閱讀 2608·2019-08-30 15:55
閱讀 2265·2019-08-30 15:53
閱讀 2301·2019-08-29 17:13
閱讀 2762·2019-08-29 16:31
閱讀 2955·2019-08-29 12:24