知道了Python多線程和進(jìn)程宵距,你可能不知道協(xié)程的存在

image

@Author: runsen

協(xié)程是實(shí)現(xiàn)并發(fā)編程的一種方式腊尚。

https://docs.python.org/zh-cn/3/library/asyncio.html

一說并發(fā),你肯定想到了多線程 满哪, 多進(jìn)程模型婿斥,沒錯(cuò),多線程 和 多進(jìn)程哨鸭,正是解決并發(fā)問題的經(jīng)典模型之一

但是你了解過協(xié)程Coroutine嗎民宿?

協(xié)程:是單線程下的并發(fā),又稱微線程像鸡。

就是只有一個(gè)線程活鹰,如何提高速度,解決并發(fā)編程

英文名Coroutine坟桅。

協(xié)程比線程的單位更小——協(xié)程

注意協(xié)程這個(gè)概念完全是程序員自己想出來的東西华望,它對于操作系統(tǒng)來說根本不存在。操作系統(tǒng)只有進(jìn)程和線程仅乓。

從一個(gè)demo學(xué)起

import time 

def print_num(num):
    print("Maoli is printing " + str(num) + " nows" )
    time.sleep(1)
    print("Maoli prints" + str(num) + " OK")

def main(nums):
    for num in nums:
        print_num(num)
%time main([i for i in range(1,6)])


Maoli is printing 1 nows
Maoli prints1 OK
Maoli is printing 2 nows
Maoli prints2 OK
Maoli is printing 3 nows
Maoli prints3 OK
Maoli is printing 4 nows
Maoli prints4 OK
Maoli is printing 5 nows
Maoli prints5 OK
Wall time: 5 s

%time 需要在jupyter notebook中運(yùn)行赖舟。

上面代碼是從上到下執(zhí)行的。

下面將上面代碼改為協(xié)程版

注意py版本3.7以上夸楣,主要使用的是asyncio

import asyncio

async def print_num(num):
    print("Maoli is printing " + str(num) + " nows" )
    await asyncio.sleep(1)
    print("Maoli prints" + str(num) + " OK")

async def main(nums):
    for num in nums:
        await print_num(num)
%time asyncio.run(main([i for i in range(1,6)]))


Maoli is printing 1 nows
Maoli prints1 OK
Maoli is printing 2 nows
Maoli prints2 OK
Maoli is printing 3 nows
Maoli prints3 OK
Maoli is printing 4 nows
Maoli prints4 OK
Maoli is printing 5 nows
Maoli prints5 OK
Wall time: 5.01 s

asyncio.run() 函數(shù)用來運(yùn)行最高層級(jí)的入口點(diǎn) "main()" 函數(shù)

await 是同步調(diào)用等待一個(gè)協(xié)程宾抓。以下代碼段會(huì)在等待 1 秒后打印 num,速度上沒有發(fā)生改變豫喧。

需要引入asyncio.create_task才可以

可等待對象

如果一個(gè)對象可以在 await 語句中使用石洗,那么它就是 可等待 對象

協(xié)程中的還一個(gè)重要概念,任務(wù)(Task)

如果寫一個(gè)數(shù)字是一個(gè)任務(wù)紧显,那么毛利我要完成5個(gè)任務(wù)

毛利我寫個(gè)1-5都這么慢讲衫,不行,我要加速寫

asyncio.create_task() 函數(shù)用來并發(fā)運(yùn)行作為 asyncio 任務(wù) 的多個(gè)協(xié)程孵班。

import asyncio

async def print_num(num):
    print("Maoli is printing " + str(num) + " nows" )
    await asyncio.sleep(1)
    print("Maoli prints" + str(num) + " OK")

async def main(nums):
    tasks = [asyncio.create_task(print_num(num)) for num in nums]
    for task in tasks:
        await task
%time asyncio.run(main([i for i in range(1,6)]))


Maoli is printing 1 nows
Maoli is printing 2 nows
Maoli is printing 3 nows
Maoli is printing 4 nows
Maoli is printing 5 nows
Maoli prints1 OK
Maoli prints3 OK
Maoli prints5 OK
Maoli prints2 OK
Maoli prints4 OK
Wall time: 1.01 s

還可以寫成await asyncio.gather(*tasks)這種方法

import asyncio

async def print_num(num):
    print("Maoli is printing " + str(num) + " nows" )
    await asyncio.sleep(1)
    print("Maoli prints" + str(num) + " OK")

async def main(nums):
    tasks = [asyncio.create_task(print_num(num)) for num in nums]
    await asyncio.gather(*tasks)
%time asyncio.run(main([i for i in range(1,6)]))

*tasks 解包列表涉兽,將列表變成了函數(shù)的參數(shù);與之對應(yīng)的是篙程, ** dict 將字典變成了函數(shù)的參數(shù)枷畏。

asyncio 隊(duì)列

asyncio也是只有在Pytohn3.7才有的東西。

asyncio 隊(duì)列被設(shè)計(jì)成與 queue 模塊類似虱饿。

import asyncio
import random

async def consumer(queue, id):
    while True:
        val = await queue.get()
        print('{} get a val: {}'.format(id, val))
        await asyncio.sleep(1)

async def producer(queue, id):
    for i in range(5):
        val = random.randint(1, 10)
        await queue.put(val)
        print('{} put a val: {}'.format(id, val))
        await asyncio.sleep(1)

async def main():
    # 創(chuàng)建隊(duì)列
    queue = asyncio.Queue()
    # 消費(fèi)者1號(hào)
    consumer_1 = asyncio.create_task(consumer(queue, 'consumer_1'))
    # 消費(fèi)者2號(hào)
    consumer_2 = asyncio.create_task(consumer(queue, 'consumer_2'))
    # 生產(chǎn)者1號(hào)
    producer_1 = asyncio.create_task(producer(queue, 'producer_1'))
    # 生產(chǎn)者2號(hào)
    producer_2 = asyncio.create_task(producer(queue, 'producer_2'))
    # stop 10秒
    await asyncio.sleep(10)
    consumer_1.cancel()
    consumer_2.cancel()
    
    await asyncio.gather(consumer_1, consumer_2, producer_1, producer_2, return_exceptions=True)

%time asyncio.run(main())

協(xié)程的寫法簡潔清晰拥诡,只要把 async / await 語法和 create_task 結(jié)合來用触趴,就是Python中比較常見的協(xié)程

如果不會(huì)多線程,看我之前文章

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末渴肉,一起剝皮案震驚了整個(gè)濱河市冗懦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宾娜,老刑警劉巖批狐,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異前塔,居然都是意外死亡嚣艇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門华弓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來食零,“玉大人,你說我怎么就攤上這事寂屏》∫ィ” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵迁霎,是天一觀的道長吱抚。 經(jīng)常有香客問我,道長考廉,這世上最難降的妖魔是什么秘豹? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮昌粤,結(jié)果婚禮上既绕,老公的妹妹穿的比我還像新娘。我一直安慰自己涮坐,他們只是感情好凄贩,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著袱讹,像睡著了一般疲扎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上捷雕,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天椒丧,我揣著相機(jī)與錄音,去河邊找鬼非区。 笑死瓜挽,一個(gè)胖子當(dāng)著我的面吹牛盹廷,可吹牛的內(nèi)容都是我干的征绸。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼管怠!你這毒婦竟也來了淆衷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤渤弛,失蹤者是張志新(化名)和其女友劉穎祝拯,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體她肯,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡佳头,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晴氨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片康嘉。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖籽前,靈堂內(nèi)的尸體忽然破棺而出亭珍,到底是詐尸還是另有隱情,我是刑警寧澤枝哄,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布肄梨,位于F島的核電站,受9級(jí)特大地震影響挠锥,放射性物質(zhì)發(fā)生泄漏众羡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一瘪贱、第九天 我趴在偏房一處隱蔽的房頂上張望纱控。 院中可真熱鬧,春花似錦菜秦、人聲如沸甜害。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽尔店。三九已至,卻和暖如春主慰,著一層夾襖步出監(jiān)牢的瞬間嚣州,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工共螺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留该肴,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓藐不,卻偏偏與公主長得像匀哄,于是被迫代替她去往敵國和親秦效。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容