99偷拍视频精品区一区二,口述久久久久久久久久久久,国产精品夫妇激情啪发布,成人永久免费网站在线观看,国产精品高清免费在线,青青草在线观看视频观看,久久久久久国产一区,天天婷婷久久18禁,日韩动漫av在线播放直播

python協程函數切換 python協程返回值

python協程(4):asyncio

asyncio是官方提供的協程的類庫,從python3.4開始支持該模塊

創新互聯公司是一家專業提供徐水企業網站建設,專注與成都做網站、成都網站制作、H5建站、小程序制作等業務。10年已為徐水眾多企業、政府機構等服務。創新互聯專業網站建設公司優惠進行中。

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協程gevent怎么用

在學習gevent之前,你肯定要知道你學的這個東西是什么。

官方描述gevent

gevent is a coroutine-based Python networking library that uses greenlet to provide a high-level synchronous API on top of the libev event loop.

翻譯:gevent是一個基于協程的Python網絡庫。我們先理解這句,也是這次學習的重點——協程。

wiki描述協程

與子例程一樣,協程也是一種程序組件。相對子例程而言,協程更為一般和靈活,但在實踐中使用沒有子例程那樣廣泛。子例程的起始處是惟一的入口點,一旦退出即完成了子例程的執行,子例程的一個實例只會返回一次;協程可以通過yield來調用其它協程。通過yield方式轉移執行權的協程之間不是調用者與被調用者的關系,而是彼此對稱、平等的。協程允許多個入口點,可以在指定位置掛起和恢復執行。

沒看懂?沒關系,我也沒看懂,不過算是有點線索:子例程。

子例程

過程有兩種,一種叫子例程(Subroutine),通常叫Sub;另一種叫函數(Function)。底層實現機制是一樣的,區別在于,Sub只執行操作,沒有返回值;Function不但執行操作,并且有返回值。用過VB的應該會比較清楚這點。(原諒我用了百度百科)說到底子例程就是過程,我們一般叫它函數。

說到函數,我就想吐槽了,不明白為什么要叫函數。很多時候我們寫一個函數是為了封裝、模塊化某個功能,它是一個功能、或者說是一個過程。因為它包含的是類似于流程圖那樣的具體邏輯,先怎樣做,然后怎樣做;如果遇到A情況則怎樣,如果遇到B情況又怎樣。個人覺得還是叫過程比較好,叫做函數就讓人很糾結了,難道因為回歸到底層還是計算問題,出于數學的角度把它稱為函數?這個略坑啊!為了符合大家的口味,我還是稱之為函數好了(其實我也習慣叫函數了%_

講到函數,我們就往底層深入一點,看看下面的代碼:

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

def a():

print "a start"

b()

print "a end"

def b():

print "b start"

c()

print "b end"

def c():

print "c start"

print "c end"

if __name__ == "__main__":

a()

a start

b start

c start

c end

b end

a end

對于這樣的結果大家肯定不會意外的。每當函數被調用,就會在棧中開辟一個棧空間,調用結束后再回收該空間。

假設一個這樣的場景:有個講臺,每個人都可以上去發表言論,但是每次講臺只能站一個人。現在a在上面演講,當他說到“大家好!”的時候,b有個緊急通知要告訴大家,所以a就先下來讓b講完通知,然后a再上講臺繼續演講。如果用函數的思想模擬這個問題,堆棧示意圖是這樣的:

大家會不會發現問題,就是b通知完a繼續演講都要重新開始。因為函數在重新調用的時候,它的局部變量是會被重置的,對于之前他說的那句“大家好”,他是不會記得的(可能a的記性不好)。那有沒有什么辦法可以不讓他重復,而是在打斷之后繼續呢?很簡單,在他走下講臺之前記住當前說過的話。表現在函數中就是在退出之前,保存該函數的局部變量,方便在重新進入該函數的時候,能夠從之前的局部變量開始繼續執行。

升級版

如果你有一段代碼生產數據,另外一段代碼消費數據,哪個應該是調用者,哪個應該是被調用者?

例如:生產者 —— 消費者問題,先拋開進程、線程等實現方法。假設有兩個函數producer和consumer,當緩沖區滿了,producer調用consumer,當緩沖區空了,consumer調用producer,但是這樣的函數互相調用會出什么問題?

Python

1

2

3

4

5

6

7

8

def producer():

print "生產一個"

consumer()

def consumer():

print "消費一個"

producer()

producer生產一個,緩沖區滿了,consumer消費一個,緩沖區空了,producer生產一個,如此循環。會看到下面這樣的圖:

看起來好像不錯,感覺兩個函數協調運行的很好,很好的解決了生產者——消費者問題。如果真有這么好也就不會有協程的存在了,仔細分析會有兩個問題:

無限次數的函數嵌套調用,而沒有函數返回,會有什么樣的后果?

兩個函數貌似協調有序的工作,你來我往,但每次執行的都是同一個函數實例嗎?

首先,上面的偽代碼示例是一個無限的函數嵌套調用,沒有函數返回來釋放棧,棧的空間不斷的在增長,直到溢出,程序崩潰。然后,看起來兩個函數協調有序,事實上操作的都不是同一個實例對象,不知道下面的圖能否看懂。

那什么東西有這樣的能力呢?我們很快就可以想到進程、線程,但是你真的想使用進程、線程如此重量級的東西在這么簡單的程序上嗎?野蠻的搶占式機制和笨重的上下文切換!

還有一種程序組件,那就是協程。它能保留上一次調用時的狀態,每次重新進入該過程的時候,就相當于回到上一次離開時所處邏輯流的位置。協程的起始處是第一個入口點,在協程里,返回點之后是接下來的入口點。協程的生命期完全由他們的使用的需要決定。每個協程在用yield命令向另一個協程交出控制時都盡可能做了更多的工作,放棄控制使得另一個協程從這個協程停止的地方開始,接下來的每次協程被調用時,都是從協程返回(或yield)的位置接著執行。

從上面這些你就可以知道其實協程是模擬了多線程(或多進程)的操作,多線程在切換的時候都會有一個上下文切換,在退出的時候將現場保存起來,等到下一次進入的時候從保存的現場開始,繼續執行。

看下協程是怎樣實現的:

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

import random

from time import sleep

from greenlet import greenlet

from Queue import Queue

queue = Queue(1)

@greenlet

def producer():

chars = ['a', 'b', 'c', 'd', 'e']

global queue

while True:

char = random.choice(chars)

queue.put(char)

print "Produced: ", char

sleep(1)

consumer.switch()

@greenlet

def consumer():

global queue

while True:

char = queue.get()

print "Consumed: ", char

sleep(1)

producer.switch()

if __name__ == "__main__":

producer.run()

consumer.run()

應用場景

我們一直都在大談協程是什么樣一個東西,卻從沒有提起協程用來干嘛,這個其實大家分析一下就能夠知道。從上面的生產者——消費者問題應該能看出,它分別有兩個任務,假設交給兩個人去執行,但每次只能允許一個人行動。當緩沖區滿的時候,生產者是出于等待狀態的,這個時候可以將執行任務的權利轉交給消費者,當緩沖區空得時候,消費者是出于等待狀態的,這個時候可以將執行任務的權利轉交給生產者,是不是很容易聯想到多任務切換?然后想到線程?最后想到高并發?

但同學們又會問,既然有了線程為什么還要協程呢?因為線程是系統級別的,在做切換的時候消耗是特別大的,具體為什么這么大等我研究好了再告訴你;同時線程的切換是由CPU決定的,可能你剛好執行到一個地方的時候就要被迫終止,這個時候你需要用各種措施來保證你的數據不出錯,所以線程對于數據安全的操作是比較復雜的。而協程是用戶級別的切換,且切換是由自己控制,不受外力終止。

總結

協程其實模擬了人類活動的一種過程。例如:你準備先寫文檔,然后修復bug。這時候接到電話說這個bug很嚴重,必須立即修復(可以看作CPU通知)。于是你暫停寫文檔,開始去填坑,終于你把坑填完了,你回來寫文檔,這個時候你肯定是接著之前寫的文檔繼續,難道你要把之前寫的給刪了,重新寫?這就是協程。那如果是子例程呢?那你就必須重新寫了,因為退出之后,棧幀就會被彈出銷毀,再次調用就是開辟新的棧空間了。

總結:協程就是用戶態下的線程,是人們在有了進程、線程之后仍覺得效率不夠,而追求的又一種高并發解決方案。為什么說是用戶態,是因為操作系統并不知道它的存在,它是由程序員自己控制、互相協作的讓出控制權而不是像進程、線程那樣由操作系統調度決定是否讓出控制權。

Python異步編程4:協程函數,協程對象,await關鍵字

協程函數:async def?函數名。3.5+

協程對象:執行協程函數()得到的協程對象。

3.5之后的寫法:

3.7之后的寫法:更簡便

await后面?跟?可等待的對象。(協程對象,Future,Task對象?約等于IO等待)

await實例2:串行執行。 一個協程函數里面可以支持多個await ,雖然會串行,但是如果有其他協程函數,任務列表也在執行,依然會切換。只是案例中的main對應執行的others1和others2串行 。 await會等待對象的值得到之后才繼續往下走。

python 中的協程是怎么實現多任務的?

協程也稱為微線程,是在一個線程中,通過不斷的切換任務函數實現了多任務的效果。

協程在python實現的原理主要是通過yield這個關鍵字實現

但是真正在開發時,可以不需要自己實現,可以通過很多成熟的第三方模塊來實現協程,比如greenlet,gevent等模塊。多線程的課程我記得是在黑馬程序員里面找的,一套,還有資料。

python中多進程+協程的使用以及為什么要用它

python里推薦用多進程而不是多線程,但是多進程也有其自己的限制:相比線程更加笨重、切換耗時更長,并且在python的多進程下,進程數量不推薦超過CPU核心數(一個進程只有一個GIL,所以一個進程只能跑滿一個CPU),因為一個進程占用一個CPU時能充分利用機器的性能,但是進程多了就會出現頻繁的進程切換,反而得不償失。

不過特殊情況(特指IO密集型任務)下,多線程是比多進程好用的。

舉個例子:給你200W條url,需要你把每個url對應的頁面抓取保存起來,這種時候,單單使用多進程,效果肯定是很差的。為什么呢?

例如每次請求的等待時間是2秒,那么如下(忽略cpu計算時間):

1、單進程+單線程:需要2秒*200W=400W秒==1111.11個小時==46.3天,這個速度明顯是不能接受的

2、單進程+多線程:例如我們在這個進程中開了10個多線程,比1中能夠提升10倍速度,也就是大約4.63天能夠完成200W條抓取,請注意,這里的實際執行是:線程1遇見了阻塞,CPU切換到線程2去執行,遇見阻塞又切換到線程3等等,10個線程都阻塞后,這個進程就阻塞了,而直到某個線程阻塞完成后,這個進程才能繼續執行,所以速度上提升大約能到10倍(這里忽略了線程切換帶來的開銷,實際上的提升應該是不能達到10倍的),但是需要考慮的是線程的切換也是有開銷的,所以不能無限的啟動多線程(開200W個線程肯定是不靠譜的)

3、多進程+多線程:這里就厲害了,一般來說也有很多人用這個方法,多進程下,每個進程都能占一個cpu,而多線程從一定程度上繞過了阻塞的等待,所以比單進程下的多線程又更好使了,例如我們開10個進程,每個進程里開20W個線程,執行的速度理論上是比單進程開200W個線程快10倍以上的(為什么是10倍以上而不是10倍,主要是cpu切換200W個線程的消耗肯定比切換20W個進程大得多,考慮到這部分開銷,所以是10倍以上)。

還有更好的方法嗎?答案是肯定的,它就是:

4、協程,使用它之前我們先講講what/why/how(它是什么/為什么用它/怎么使用它)

what:

協程是一種用戶級的輕量級線程。協程擁有自己的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧。因此:

協程能保留上一次調用時的狀態(即所有局部狀態的一個特定組合),每次過程重入時,就相當于進入上一次調用的狀態,換種說法:進入上一次離開時所處邏輯流的位置。

在并發編程中,協程與線程類似,每個協程表示一個執行單元,有自己的本地數據,與其它協程共享全局數據和其它資源。

why:

目前主流語言基本上都選擇了多線程作為并發設施,與線程相關的概念是搶占式多任務(Preemptive multitasking),而與協程相關的是協作式多任務。

不管是進程還是線程,每次阻塞、切換都需要陷入系統調用(system call),先讓CPU跑操作系統的調度程序,然后再由調度程序決定該跑哪一個進程(線程)。而且由于搶占式調度執行順序無法確定的特點,使用線程時需要非常小心地處理同步問題,而協程完全不存在這個問題(事件驅動和異步程序也有同樣的優點)。

因為協程是用戶自己來編寫調度邏輯的,對CPU來說,協程其實是單線程,所以CPU不用去考慮怎么調度、切換上下文,這就省去了CPU的切換開銷,所以協程在一定程度上又好于多線程。

how:

python里面怎么使用協程?答案是使用gevent,使用方法:看這里

使用協程,可以不受線程開銷的限制,我嘗試過一次把20W條url放在單進程的協程里執行,完全沒問題。

所以最推薦的方法,是多進程+協程(可以看作是每個進程里都是單線程,而這個單線程是協程化的)

多進程+協程下,避開了CPU切換的開銷,又能把多個CPU充分利用起來,這種方式對于數據量較大的爬蟲還有文件讀寫之類的效率提升是巨大的。

python里協程事件循環里怎么樣調用非協程函數

為了管理協程和I/O的回調函數,asyncio庫的事件循環也能基于定時的方式調用普通的函數,使用call_soon()函數,例子如下:

import?asyncio??

import?functools??

def?callback(arg,?*,?kwarg='default'):??

print('callback?invoked?with?{}?and?{}'.format(arg,?kwarg))??

async?def?main(loop):??

print('registering?callbacks')??

loop.call_soon(callback,?1)??

wrapped?=?functools.partial(callback,?kwarg='not?default')??

loop.call_soon(wrapped,?2)??

await?asyncio.sleep(0.1)??

event_loop?=?asyncio.get_event_loop()??

try:??

print('entering?event?loop')??

event_loop.run_until_complete(main(event_loop))??

finally:??

print('closing?event?loop')??

event_loop.close()

結果輸出如下:

entering event loop

registering callbacks

callback invoked with 1 and default

callback invoked with 2 and not default

closing event loop

當前標題:python協程函數切換 python協程返回值
本文地址:http://www.yijiale78.com/article18/doddegp.html

成都網站建設公司_創新互聯,為您提供自適應網站全網營銷推廣動態網站網頁設計公司小程序開發營銷型網站建設

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

成都做網站