日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

【Python進(jìn)階學(xué)習(xí)】—協(xié)程

系統(tǒng) 2203 0

前言

前面的文章提到過(guò),python使用多線程,會(huì)因?yàn)镚IL的原因?qū)е露嗑€程的使用效率低下,甚至比單個(gè)線程的處理速度還慢。然而在python編程中, 為了解決多線程之間上下文切換的開(kāi)銷(xiāo),以及增加線程控制的靈活性,python引入了協(xié)程 。本文我們就來(lái)說(shuō)一說(shuō)python協(xié)程的特點(diǎn)和使用方法。

?

一、協(xié)程定義

定義:協(xié)程(Coroutine),又稱(chēng)微線程。協(xié)程的作用,是在執(zhí)行函數(shù)A時(shí),可以隨時(shí)中斷,去執(zhí)行函數(shù)B,然后中斷繼續(xù)執(zhí)行函數(shù)A(可以自由切換)。但這一過(guò)程并不是函數(shù)調(diào)用(沒(méi)有調(diào)用語(yǔ)句),這一整個(gè)過(guò)程看似像多線程,然而協(xié)程只有一個(gè)線程執(zhí)行。

無(wú)論多線程和多進(jìn)程,IO的調(diào)度更多取決于系統(tǒng),而 協(xié)程的方式,調(diào)度來(lái)自用戶(hù) ,用戶(hù)可以在函數(shù)中yield一個(gè)狀態(tài)。使用協(xié)程可以實(shí)現(xiàn)高效的并發(fā)任務(wù)。

?

二、協(xié)程的實(shí)現(xiàn)

Python的在3.4中引入了協(xié)程的概念,可是這個(gè)還是以生成器對(duì)象為基礎(chǔ),3.5則確定了協(xié)程的語(yǔ)法。

實(shí)現(xiàn)協(xié)程通常可以引入一些python庫(kù)來(lái)實(shí)現(xiàn),其中最常用的就是asyncio,當(dāng)然也有一些其他的如tornado和gevent都實(shí)現(xiàn)了類(lèi)似的功能。這里我們就來(lái)了解一下asyncio

協(xié)程通過(guò) async/await 語(yǔ)法進(jìn)行聲明 ,是編寫(xiě)異步應(yīng)用的推薦方式。我們先來(lái)了解asyncio的幾個(gè)概念名詞:

            
              event_loop 事件循環(huán):程序開(kāi)啟一個(gè)無(wú)限的循環(huán),程序員會(huì)把一些函數(shù)注冊(cè)到事件循環(huán)上。當(dāng)滿(mǎn)足事件發(fā)生的時(shí)候,調(diào)用相應(yīng)的協(xié)程函數(shù)。

coroutine 協(xié)程:協(xié)程對(duì)象,指一個(gè)使用async關(guān)鍵字定義的函數(shù),它的調(diào)用不會(huì)立即執(zhí)行函數(shù),而是會(huì)返回一個(gè)協(xié)程對(duì)象。協(xié)程對(duì)象需要注冊(cè)到事件循環(huán),由事件循環(huán)調(diào)用。

task 任務(wù):一個(gè)協(xié)程對(duì)象就是一個(gè)原生可以?huà)炱鸬暮瘮?shù),任務(wù)則是對(duì)協(xié)程進(jìn)一步封裝,其中包含任務(wù)的各種狀態(tài)。

future: 代表將來(lái)執(zhí)行或沒(méi)有執(zhí)行的任務(wù)的結(jié)果。它和task上沒(méi)有本質(zhì)的區(qū)別

async/await 關(guān)鍵字:python3.5 用于定義協(xié)程的關(guān)鍵字,async定義一個(gè)協(xié)程,await用于掛起阻塞的異步調(diào)用接口。
            
          

為了解釋上面的名詞,我們一步步來(lái)實(shí)現(xiàn)簡(jiǎn)單的異步編程:

1、定義一個(gè)協(xié)程

            
              import time
import asyncio

# 定義一個(gè)協(xié)程并創(chuàng)建一個(gè)事件循環(huán)
loop = asyncio.get_event_loop()

# 協(xié)程對(duì)象coroutine需要在事件循環(huán)里面才能執(zhí)行
loop.run_until_complete(coroutine)

            
          

2、協(xié)程對(duì)象

            
              async def sync_func(x):
    print('Waiting: ', x)

# 實(shí)例化一個(gè)協(xié)程對(duì)象
coroutine = sync_func(2)
            
          

由上面可以得出, 用async修飾的方法是一個(gè)協(xié)程對(duì)象,協(xié)程對(duì)象需要在協(xié)程的事件循環(huán)里面才能運(yùn)行

3、創(chuàng)建一個(gè)task

            
              task = asyncio.ensure_future(coroutine)
loop.run_until_complete(task)
            
          

事件循環(huán)除了可以運(yùn)行協(xié)程對(duì)象,也可以運(yùn)行任務(wù)。

在這里 task只是對(duì)協(xié)程對(duì)象coroutine進(jìn)行了封裝,task還可以綁定協(xié)程對(duì)象執(zhí)行后的回調(diào),甚至還可以封裝成list數(shù)組等 ,逐個(gè)進(jìn)行事件循環(huán)調(diào)用。

4、task綁定回調(diào)函數(shù)

            
              def callback(x):
    print(x)

task = asyncio.ensure_future(coroutine)
task.add_done_callback(functools.partial(callback, 2))
loop.run_until_complete(task)
            
          

其中callback是回調(diào)函數(shù),執(zhí)行完協(xié)程之后會(huì)執(zhí)行回調(diào)函數(shù)。綁定回調(diào)也是用task封裝協(xié)程對(duì)象的一個(gè)好處

5、協(xié)程的阻塞和await

            
              async def sync_func(x):
    print('Waiting: ', x)
    await asyncio.sleep(x)
    return 'Done after {}s'.format(x)


coroutine = sync_func(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine)
loop.run_until_complete(task)
            
          

如上所述,如果協(xié)程對(duì)象函數(shù)里面帶有 await ,是可以實(shí)現(xiàn)協(xié)程的運(yùn)行阻塞的。上面例子執(zhí)行結(jié)果是print之后sleep了2秒,這 期間可以讓出控制器,loop可以去調(diào)用別的協(xié)程 ,然后再回來(lái)執(zhí)行return,return的結(jié)果可以用task.result()來(lái)獲取。

6、多個(gè)協(xié)程并發(fā)執(zhí)行

            
              async def sync_func(x):
    print('Waiting: ', x)

    await asyncio.sleep(x)
    return 'Done after {}s'.format(x)

start = now()

coroutine1 = sync_func(1)
coroutine2 = sync_func(2)

tasks = [
    asyncio.ensure_future(coroutine1),
    asyncio.ensure_future(coroutine2)
]

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
            
          

上述例子執(zhí)行結(jié)果為:協(xié)程1print之后阻塞,再協(xié)程2print后也阻塞,最后協(xié)程1return,協(xié)程2再return。

7、協(xié)程停止:?jiǎn)?dòng)事件循環(huán)之后,馬上ctrl+c,會(huì)觸發(fā)run_until_complete的執(zhí)行異常 KeyBorardInterrupt。然后通過(guò)循環(huán)asyncio.Task取消future。

            
              try:
    loop.run_until_complete(asyncio.wait(tasks))
except KeyboardInterrupt as e:
    loop.stop()
    loop.run_forever()
finally:
    loop.close()
            
          

?

三、協(xié)程的使用場(chǎng)景

1、當(dāng)一個(gè)程序變得很大而且復(fù)雜時(shí),將其劃分為子程序,每一部分實(shí)現(xiàn)特定的任務(wù)是個(gè)不錯(cuò)的方案。 子程序不能單獨(dú)執(zhí)行,只能在主程序的請(qǐng)求下執(zhí)行,主程序負(fù)責(zé)協(xié)調(diào)使用各個(gè)子程序 。協(xié)程就是子程序的泛化。和子程序一樣的事,協(xié)程只負(fù)責(zé)計(jì)算任務(wù)的一步;和子程序不一樣的是,協(xié)程沒(méi)有主程序來(lái)進(jìn)行調(diào)度。

? ? ? ? ?? 【Python進(jìn)階學(xué)習(xí)】—協(xié)程_第1張圖片

2、異步爬蟲(chóng)
  很多關(guān)心協(xié)程的朋友,大部分是用其寫(xiě)爬蟲(chóng),這是因?yàn)閰f(xié)程能很好的解決IO阻塞問(wèn)題。那么對(duì)于異步爬蟲(chóng)的需求,使用協(xié)程的方法大致如下:
(1)grequests;
(2)爬蟲(chóng)模塊+gevent;
(3)aiohttp;
(4)scrapy框架+asyncio模塊

3、協(xié)程池

類(lèi)似于gevent,我們可以先創(chuàng)建好協(xié)程,放入一個(gè)協(xié)程池中,每次有任務(wù)請(qǐng)求的時(shí)候都由協(xié)程去執(zhí)行,主線程進(jìn)行統(tǒng)一管理和調(diào)度,這在一下I/O密集型的數(shù)據(jù)清洗等工作中可以提高很多效率。

?

四、協(xié)程的優(yōu)缺點(diǎn)

1、執(zhí)行效率高,因?yàn)樽映绦蚯袚Q(函數(shù))不是線程切換,由程序自身控制,沒(méi)有切換線程的開(kāi)銷(xiāo)。所以與多線程相比,線程的數(shù)量越多,協(xié)程性能的優(yōu)勢(shì)越明顯;
2、不需要多線程的鎖機(jī)制,因?yàn)橹挥幸粋€(gè)線程,也不存在同時(shí)寫(xiě)變量沖突,在控制共享資源時(shí)也不需要加鎖,因此執(zhí)行效率高很多。

3、缺點(diǎn): 無(wú)法利用多核資源 ,協(xié)程的本質(zhì)是個(gè)單線程,它不能同時(shí)將 單個(gè)CPU 的多個(gè)核用上,協(xié)程需要和進(jìn)程配合才能運(yùn)行在多CPU上。

4、 進(jìn)行阻塞(Blocking)操作(如IO時(shí))會(huì)阻塞掉整個(gè)程序

參考鏈接:

https://thief.one/2017/02/20/Python%E5%8D%8F%E7%A8%8B/

https://www.jianshu.com/p/7690edfe9ba5

?


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 益阳市| 华阴市| 天长市| 孟州市| 合阳县| 西华县| 图们市| 枞阳县| 顺义区| 霍城县| 西乡县| 遂平县| 美姑县| 诸城市| 焉耆| 华坪县| 九江县| 西充县| 漠河县| 利津县| 独山县| 桦甸市| 内黄县| 亚东县| 临潭县| 建湖县| 垦利县| 缙云县| 潜山县| 专栏| 沁源县| 延边| 东乡| 昭通市| 通化市| 务川| 凌云县| 万安县| 彰化市| 临桂县| 根河市|