目錄
概念:
產生器實作協程原理
greenlet 的引入
#gevent協程
gevent 協程通訊
首頁 後端開發 Python教學 深入了解python中的協程函數

深入了解python中的協程函數

Apr 14, 2018 am 11:16 AM
python 函數 協程

這篇文章給大家分享的內容是深入了解python中的協程函數,有著一定的參考價值,有需要的朋友可以參考一下

概念:

根據維基百科給出的定義,「協程是為非搶佔式多任務產生子程式的電腦程式元件,協程允許不同入口點在不同位置暫停或開始執行程式」。從技術的角度來說,「協程就是你可以暫停執行的函數」。如果你把它理解成“就像生成器一樣”,那麼你就想對了。

協程,又稱為微線程,看上去像是子程序,但是它和子程序又不太一樣,它在執行的過程中,可以在中斷當前的子程序後去執行別的子程序,再返回來執行之前的子程序,但是它的相關資訊還是之前的。

協程不同於執行緒,執行緒是搶佔式的調度,而協程是協同式的調度,協程則需要自己做調度。 
子程式呼叫總是一個入口,一次返回,呼叫順序是明確的。而協程的呼叫和子程序不同。協程看起來也是子程序,但執行過程中,在子程序內部可中斷,然後轉而執行別的子程序,在適當的時候再返回來接著執行。

協程的優點:

  • 協程優勢是極高的執行效率。因為子程式切換不是執行緒切換,而是由程式本身控制,因此,沒有執行緒切換的開銷,和多執行緒比,執行緒數量越多,協程的效能優勢就越明顯。用來執行協程多任務非常適合。

  • 協程沒有執行緒的安全性問題。一個行程可以同時存在多個協程,但是只有一個協程是啟動的,而且協程的啟動和休眠又是程式設計師透過程式設計來控制,而不是作業系統控制的。

產生器實作協程原理

#範例:

def func(n):
    index=0
    if index<=n:
        c=yield 1
        print("task------{}".format(c))
        index+=1f=func(3)
n=next(f)
print(n)try:
    n=f.send(5)#程序就直接结束了
    print("n是{}".format(n))except StopIteration as e:    pass
登入後複製
输出打印:1task------5
登入後複製

解釋說明:

  • 很明顯func是一個產生器,send方法有一個參數,該參數指定的是上一次被掛起的yield語句的回傳值。

  • send需要做例外處理。

  • 總的來說,send方法和next方法唯一的差別在於執行send方法會先把上一次掛起的yield語句的回傳值透過參數設定,從而實現與生成器方法的交互作用。但要注意,在一個生成器物件沒有執行next方法之前,由於沒有yield語句被掛起,所以執行send方法會報錯。

  • send方法的參數為None時,它與next方法完全等價。

生成器實作生產者與消費者模式:

def cunsumer():
    while True:
        n=yield 3
        if not n:            return
        print(&#39;cunsumer{}&#39;.format(n))def product(c):
    c.send(None)
    n=0
    while n<5:
        n=n+1
        r=c.send(n)
        print("product{}".format(r))
    c.close()
c=cunsumer()
product(c)
登入後複製
打印:
cunsumer1
product3
cunsumer2
product3
cunsumer3
product3
cunsumer4
product3
cunsumer5
product3
登入後複製

說明:

在生產者先執行了c.send(None),目的是先讓消費者掛起,再用send傳值,第一次傳1,消費者那裡打印1,生產者打印r是消費者yield後面的值。

greenlet 的引入

雖然CPython(標準Python)能夠透過生成器來實現協程,但使用起來還並不是很方便。

同時,Python的一個衍生版 Stackless Python實作了原生的協程,它更有利於使用。

於是,大家開始將 Stackless 中關於協程的程式碼  單獨拿出來做成了CPython的擴充包。

這就是 greenlet 的由來,因此 greenlet 是底層實作了原生協程的 C擴充函式庫。

程式碼示意:

from greenlet import greenletimport randomimport timedef Producer():
    while True:
        item = random.randint(0,10)
        print("生产了{}".format(item))
        c.switch(item)#切换到消费者,并将item传入消费者
        time.sleep(1)def consumer():
    print(&#39;我先执行&#39;)    #p.switch()
    while True:
        item = p.switch()#切换到生产者,并且等待生产者传入item
        print(&#39;消费了{}&#39;.format(item))
c = greenlet(consumer)#将一个普通函数变成一个协程p = greenlet(Producer)
c.switch()#让消费者先进入暂停状态(只有恢复了才能接收数据)
登入後複製

greenlet 的價值:

  • 高效能的原生協程

  • 語意更明確的明確切換

  • #直接將函數包裝成協程,保持原始程式碼風格

#gevent協程

雖然,我們有了基於epoll 的回呼程式設計模式,但卻很難使用。

即使我們可以透過配合 生成器協程 進行複雜的封裝,以簡化程式設計難度。
但仍然有一個大的問題: 封裝難度大,現有程式碼幾乎完全要重寫

gevent,透過封裝了 libev(基於epoll) 和 greenlet 兩個函式庫。
幫我們做好封裝,讓我們以類似執行緒的方式使用協程。

以至於我們幾乎不用重寫原來的程式碼就能充分利用 epoll 和 協程 威力。

程式碼示意:

from gevent import monkey;monkey.patch_all()#会把python标准库当中一些阻塞操作变成非阻塞import geventdef test1():
    print("11")
    gevent.sleep(4)#模拟爬虫请求阻塞
    print("33")def test2():
    print("22")
    gevent.sleep(4)
    print("44")
gevent.joinall([gevent.spawn(test1),gevent.spawn(test2)])#joinall 阻塞当前协程,执行给定的greenlet#spawn 启动协程,参数就是函数的名字
登入後複製

gevent 的價值:

遇到阻斷就切換到另一個協程繼續執行!

  • 使用基於 epoll 的 libev 來避免阻斷。

  • 使用基於 gevent 的 高效能協程 來切換執行。

  • 只在遇到阻塞的時候切換,沒有輪需的開銷,也沒有執行緒的開銷。

gevent實作並發伺服器

from gevent import monkey;monkey.patch_all()  #建议放在首行,会把python标准库当中一些阻塞操作变成非阻塞import geventimport socket


server=socket.socket()
server.bind((&#39;&#39;,6666))
server.listen(5)
print("开始监听")def readable(con,addr):
    print("客户端{}接入".format(addr))    while True:
        data=con.recv(1024)        if data:
            print(data)        else:
            con.close()            breakwhile True:
    con,addr=server.accept()
    gevent.spawn(readable,con,addr)#将readable函数变为协程,并且把con和addr传入其中。
登入後複製

gevent 協程通訊

gevent也有自己的佇列。使用方式和進線程基本上一樣。

基於gevent和佇列的生產者和消費者模式

from gevent import monkey;monkey.patch_all()import geventfrom gevent.queue import Queueimport randomdef producter(queue):
    while True:
        item=random.randint(0,99)
        print(&#39;生产了{}&#39;.format(item))
        queue.put(item)
        gevent.sleep(1)def comuser(queue):
    while True:
        item=queue.get()
        print(&#39;消费了{}&#39;.format(item))
queue=Queue()
p=gevent.spawn(producter,queue)
c=gevent.spawn(comuser,queue)
gevent.joinall([p,c])
登入後複製
打印:
生产了33消费了33生产了95消费了95生产了92消费了92...
登入後複製


相关推荐:

python中多进程+协程的使用

python中协程

Python 协程的详细用法和例子

python 协程示例

以上是深入了解python中的協程函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1665
14
CakePHP 教程
1423
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
PHP和Python:解釋了不同的範例 PHP和Python:解釋了不同的範例 Apr 18, 2025 am 12:26 AM

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

在PHP和Python之間進行選擇:指南 在PHP和Python之間進行選擇:指南 Apr 18, 2025 am 12:24 AM

PHP適合網頁開發和快速原型開發,Python適用於數據科學和機器學習。 1.PHP用於動態網頁開發,語法簡單,適合快速開發。 2.Python語法簡潔,適用於多領域,庫生態系統強大。

sublime怎麼運行代碼python sublime怎麼運行代碼python Apr 16, 2025 am 08:48 AM

在 Sublime Text 中運行 Python 代碼,需先安裝 Python 插件,再創建 .py 文件並編寫代碼,最後按 Ctrl B 運行代碼,輸出會在控制台中顯示。

PHP和Python:深入了解他們的歷史 PHP和Python:深入了解他們的歷史 Apr 18, 2025 am 12:25 AM

PHP起源於1994年,由RasmusLerdorf開發,最初用於跟踪網站訪問者,逐漸演變為服務器端腳本語言,廣泛應用於網頁開發。 Python由GuidovanRossum於1980年代末開發,1991年首次發布,強調代碼可讀性和簡潔性,適用於科學計算、數據分析等領域。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Golang vs. Python:性能和可伸縮性 Golang vs. Python:性能和可伸縮性 Apr 19, 2025 am 12:18 AM

Golang在性能和可擴展性方面優於Python。 1)Golang的編譯型特性和高效並發模型使其在高並發場景下表現出色。 2)Python作為解釋型語言,執行速度較慢,但通過工具如Cython可優化性能。

vscode在哪寫代碼 vscode在哪寫代碼 Apr 15, 2025 pm 09:54 PM

在 Visual Studio Code(VSCode)中編寫代碼簡單易行,只需安裝 VSCode、創建項目、選擇語言、創建文件、編寫代碼、保存並運行即可。 VSCode 的優點包括跨平台、免費開源、強大功能、擴展豐富,以及輕量快速。

notepad 怎麼運行python notepad 怎麼運行python Apr 16, 2025 pm 07:33 PM

在 Notepad 中運行 Python 代碼需要安裝 Python 可執行文件和 NppExec 插件。安裝 Python 並為其添加 PATH 後,在 NppExec 插件中配置命令為“python”、參數為“{CURRENT_DIRECTORY}{FILE_NAME}”,即可在 Notepad 中通過快捷鍵“F6”運行 Python 代碼。

See all articles