欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

如何理解Python中的協(xié)程

這篇文章主要介紹“如何理解Python中的協(xié)程”,在日常操作中,相信很多人在如何理解Python中的協(xié)程問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”如何理解Python中的協(xié)程”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的雙牌網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

我們?cè)?jīng)在golang關(guān)于goroutine的文章當(dāng)中簡(jiǎn)單介紹過(guò)協(xié)程的概念,我們?cè)賮?lái)簡(jiǎn)單review一下。協(xié)程又稱為是微線程,英文名是Coroutine。它和線程一樣可以調(diào)度,但是不同的是線程的啟動(dòng)和調(diào)度需要通過(guò)操作系統(tǒng)來(lái)處理。并且線程的啟動(dòng)和銷毀需要涉及一些操作系統(tǒng)的變量申請(qǐng)和銷毀處理,需要的時(shí)間比較長(zhǎng)。而協(xié)程呢,它的調(diào)度和銷毀都是程序自己來(lái)控制的,因此它更加輕量級(jí)也更加靈活。

協(xié)程有這么多優(yōu)點(diǎn),自然也會(huì)有一些缺點(diǎn),其中最大的缺點(diǎn)就是需要編程語(yǔ)言自己支持,否則的話需要開發(fā)者自己通過(guò)一些方法來(lái)實(shí)現(xiàn)協(xié)程。對(duì)于大部分語(yǔ)言來(lái)說(shuō),都不支持這一機(jī)制。go語(yǔ)言由于天然支持協(xié)程,并且支持得非常好,使得它廣受好評(píng),短短幾年時(shí)間就迅速流行起來(lái)。

對(duì)于Python來(lái)說(shuō),本身就有著一個(gè)GIL這個(gè)巨大的先天問(wèn)題。GIL是Python的全局鎖,在它的限制下一個(gè)Python進(jìn)程同一時(shí)間只能同時(shí)執(zhí)行一個(gè)線程,即使是在多核心的機(jī)器當(dāng)中。這就大大影響了Python的性能,尤其是在CPU密集型的工作上。所以為了提升Python的性能,很多開發(fā)者想出了使用多進(jìn)程+協(xié)程的方式。一開始是開發(fā)者自行實(shí)現(xiàn)的,后來(lái)在Python3.4的版本當(dāng)中,官方也收入了這個(gè)功能,因此目前可以光明正大地說(shuō),Python是支持協(xié)程的語(yǔ)言了。

生成器(generator)

生成器我們也在之前的文章當(dāng)中介紹過(guò),為什么我們介紹協(xié)程需要用到生成器呢,是因?yàn)镻ython的協(xié)程底層就是通過(guò)生成器來(lái)實(shí)現(xiàn)的。

通過(guò)生成器來(lái)實(shí)現(xiàn)協(xié)程的原因也很簡(jiǎn)單,我們都知道協(xié)程需要切換掛起,而生成器當(dāng)中有一個(gè)yield關(guān)鍵字,剛好可以實(shí)現(xiàn)這個(gè)功能。所以當(dāng)初那些自己在Python當(dāng)中開發(fā)協(xié)程功能的程序員都是通過(guò)生成器來(lái)實(shí)現(xiàn)的,我們想要理解Python當(dāng)中協(xié)程的運(yùn)用,就必須從最原始的生成器開始。

生成器我們很熟悉了,本質(zhì)上就是帶有yield這個(gè)關(guān)鍵詞的函數(shù)。

def test():     n = 0     while n < 10:         val = yield n          print('val = {}'.format(val))         n += 1

這個(gè)函數(shù)當(dāng)中如果沒(méi)有yield這個(gè)語(yǔ)句,那么它就是一個(gè)普通的Python函數(shù)。加上了val = yield n這個(gè)語(yǔ)句之后,它有什么變化呢?

我們嘗試著運(yùn)行一下:

# 調(diào)用test函數(shù)獲得一個(gè)生成器 g = test() print(next(g)) print(next(g)) print(next(g))

得到這么一個(gè)結(jié)果:

如何理解Python中的協(xié)程

輸出的0,1,2很好理解,就是通過(guò)next(g)返回的,這個(gè)也是生成器的標(biāo)準(zhǔn)用法。奇怪的是為什么val=None呢?val不應(yīng)該等于n么?

這里想不明白是正常的,因?yàn)檫@里涉及到了一個(gè)新的用法就是生成器的send方法。當(dāng)我們?cè)趛ield語(yǔ)句之前加上變量名的時(shí)候,它的含義其實(shí)是返回yield之后的內(nèi)容,再?gòu)耐饨缃邮找粋€(gè)變量。也就是說(shuō)當(dāng)我們執(zhí)行next(g)的時(shí)候,會(huì)從獲取yield之后的數(shù),當(dāng)我們執(zhí)行g(shù).send()時(shí),傳入的值會(huì)被賦值給yield之前的數(shù)。比如我們把執(zhí)行的代碼改成這樣:

g = test() print(next(g)) g.send('abc') print(next(g)) print(next(g))

我們?cè)賮?lái)看執(zhí)行的結(jié)果,會(huì)發(fā)現(xiàn)是這樣的:

如何理解Python中的協(xié)程

第一行val不再是None,而是我們剛剛傳入的abc了。

隊(duì)列調(diào)度

生成器每次在執(zhí)行到y(tǒng)ield語(yǔ)句之后都會(huì)自然掛起,我們可以利用這一點(diǎn)來(lái)當(dāng)做協(xié)程來(lái)調(diào)度。我們可以自己實(shí)現(xiàn)一個(gè)簡(jiǎn)易的隊(duì)列來(lái)模擬這個(gè)過(guò)程。

首先我們聲明一個(gè)雙端隊(duì)列,每次從隊(duì)列左邊頭部獲取任務(wù),調(diào)度執(zhí)行到掛起之后,放入到隊(duì)列末尾。相當(dāng)于我們用循環(huán)的方式輪詢執(zhí)行了所有任務(wù),并且這整個(gè)全程不涉及任何線程創(chuàng)建和銷毀的過(guò)程。

class Scheduler:     def __init__(self):         self._queue = deque()      def new_task(self, task):         self._queue.append(task)      def run(self):         while self._queue:             # 每次從隊(duì)列左側(cè)獲取task             task = self._queue.popleft()             try:                 # 通過(guò)next執(zhí)行之后放入隊(duì)列右側(cè)                 next(task)                 self._queue.append(task)             except StopIteration:                 pass    sch = Scheduler() sch.new_task(test(5)) sch.new_task(test(10)) sch.new_task(test(8)) sch.run()

這個(gè)只是一個(gè)很簡(jiǎn)易的調(diào)度方法,事實(shí)上結(jié)合上yield  from以及send功能,我們還可以實(shí)現(xiàn)出更加復(fù)雜的協(xié)程調(diào)度方式。但是我們也沒(méi)有必要一一窮盡,只需要理解最基礎(chǔ)的方法就可以了,畢竟現(xiàn)在我們使用協(xié)程一般也不會(huì)自己實(shí)現(xiàn)了,都會(huì)通過(guò)官方原生的工具庫(kù)來(lái)實(shí)現(xiàn)。

@asyncio.coroutine

在Python3.4之后的版本當(dāng)中,我們可以通過(guò)@asyncio.coroutine這個(gè)注解來(lái)將一個(gè)函數(shù)封裝成協(xié)程執(zhí)行的生成器。

在吸收了協(xié)程這個(gè)概念之后,Python對(duì)生成器以及協(xié)程做了區(qū)分。加上了@asyncio.coroutine注解的函數(shù)稱為協(xié)程函數(shù),我們可以用iscoroutinefunction()方法來(lái)判斷一個(gè)函數(shù)是不是協(xié)程函數(shù),通過(guò)這個(gè)協(xié)程函數(shù)返回的生成器對(duì)象稱為協(xié)程對(duì)象,我們可以通過(guò)iscoroutine方法來(lái)判斷一個(gè)對(duì)象是不是協(xié)程對(duì)象。

比如我把剛剛寫的函數(shù)上加上注解之后再來(lái)執(zhí)行這兩個(gè)函數(shù)都會(huì)得到True:

import asyncio  @asyncio.coroutine def test(k):     n = 0     while n < k:         yield         print('n = {}'.format(n))         n += 1          print(asyncio.iscoroutinefunction(test)) print(asyncio.iscoroutine(test(10)))

那我們通過(guò)注解將方法轉(zhuǎn)變成了協(xié)程之后,又該怎么使用呢?

一個(gè)比較好的方式是通過(guò)asynio庫(kù)當(dāng)中提供的loop工具,比如我們來(lái)看這么一個(gè)例子:

loop = asyncio.get_event_loop() loop.run_until_complete(test(10)) loop.close()

我們通過(guò)asyncio.get_event_loop函數(shù)創(chuàng)建了一個(gè)調(diào)度器,通過(guò)調(diào)度器的run相關(guān)的方法來(lái)執(zhí)行一個(gè)協(xié)程對(duì)象。我們可以run_until_complete也可以run_forever,具體怎么執(zhí)行要看我們實(shí)際的使用場(chǎng)景。

async,await和future

從Python3.5版本開始,引入了async,await和future。我們來(lái)簡(jiǎn)單說(shuō)說(shuō)它們各自的用途,其中async其實(shí)就是@asyncio.coroutine,用途是完全一樣的。同樣await代替的是yield  from,意為等待另外一個(gè)協(xié)程結(jié)束。

我們用這兩個(gè)一改,上面的代碼就成了:

async def test(k):     n = 0     while n < k:         await asyncio.sleep(0.5)         print('n = {}'.format(n))         n += 1

由于我們加上了await,所以每次在打印之前都會(huì)等待0.5秒。我們把a(bǔ)wait換成yield  from也是一樣的,只不過(guò)用await更加直觀也更加貼合協(xié)程的含義。

Future其實(shí)可以看成是一個(gè)信號(hào)量,我們創(chuàng)建一個(gè)全局的future,當(dāng)一個(gè)協(xié)程執(zhí)行完成之后,將結(jié)果存入這個(gè)future當(dāng)中。其他的協(xié)程可以await  future來(lái)實(shí)現(xiàn)阻塞。我們來(lái)看一個(gè)例子就明白了:

future = asyncio.Future()  async def test(k):     n = 0     while n < k:         await asyncio.sleep(0.5)         print('n = {}'.format(n))         n += 1     future.set_result('success')  async def log():     result = await future     print(result)   loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait([     log(),     test(5) ]))  loop.close()

在這個(gè)例子當(dāng)中我們創(chuàng)建了兩個(gè)協(xié)程,第一個(gè)協(xié)程是每隔0.5秒print一個(gè)數(shù)字,在print完成之后把success寫入到future當(dāng)中。第二個(gè)協(xié)程就是等待future當(dāng)中的數(shù)據(jù),之后print出來(lái)。

在loop當(dāng)中我們要調(diào)度執(zhí)行的不在是一個(gè)協(xié)程對(duì)象了而是兩個(gè),所以我們用asyncio當(dāng)中的wait將這兩個(gè)對(duì)象包起來(lái)。只有當(dāng)wait當(dāng)中的兩個(gè)對(duì)象執(zhí)行結(jié)束,wait才會(huì)結(jié)束。loop等待的是wait的結(jié)束,而wait等待的是傳入其中的協(xié)程的結(jié)束,這就形成了一個(gè)依賴循環(huán),等價(jià)于這兩個(gè)協(xié)程對(duì)象結(jié)束,loop才會(huì)結(jié)束。

到此,關(guān)于“如何理解Python中的協(xié)程”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

當(dāng)前題目:如何理解Python中的協(xié)程
URL標(biāo)題:http://aaarwkj.com/article18/gjgjgp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、微信小程序自適應(yīng)網(wǎng)站、品牌網(wǎng)站設(shè)計(jì)、微信公眾號(hào)標(biāo)簽優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化
黄色资源网日韩三级一区二区| 国产一区二区精品久久岳| 亚洲欧美精品专区极品| 日本熟女视频中文字幕| 91薄丝激情在线播放| 国产一区二区精品不卡| 日韩在线国产亚洲精品| 国产91啦中文在线观看| 中文字幕人妻丝袜一区一三区| 2021亚洲精品午夜精品国产| 亚洲成年人黄片在线播放| 一区二区三区毛片视频| 日本一区二区电影大全| 午夜激情视频福利在线观看| 久久偷拍精品视频久久| 可以免费看的日韩黄色| 五月色婷婷六月色丁香| 亚洲av日韩av高潮| 亚洲精品成人久久网| 避暑地堕落人妻中文字幕| 美女在线观看av少妇| 日韩精品人妻中文字幕满员| 小黄片视频免费在线播放| 日韩精品色av一区二区| 亚洲精品成人在线国产| av在线成人国产精品欧美| 午夜福利激情视频在线| 国产三级伦理在线播放| 一区二区三区四区蜜桃av| 亚洲中文字幕少妇熟女美妇| 国产放荡av剧情精品| 一区二区三区福利视频在线观看| 在线观看免费完整观看一区二区| 国产视频不卡一区二区| 久久亚洲精品中文字幕一| 国产a情人一区二区国产| 国产91黑丝在线视频| 亚洲欧美一区二区国产| 欧美三级欧美一级视频看| 国产熟女av一区二区| 91人妻互换一区二区|