1. 程式人生 > >實現並發-協程gevent

實現並發-協程gevent

中大 nts 替換 tar reading str end def ssl

實現並發-協程gevent

文檔地址

協程

#協程:非搶占式切換,程序切換(用戶態切換)
#沒有硬件層面的資源消耗,只是一個線程下的切換
#協程本質就是一個線程
# 1.沒有切換的消耗
# 2.沒有鎖的概念
#缺點:不能使用多核
#解決辦法:多進程+協程,在多進程裏使用協程。

# A -->B --> A
# 執行A,遇到需要切換的地方就切換到B,執行完B就切換到A繼續執行
# 這裏我們要知道,什麽時候切換,怎麽切換,怎麽保證切換回來繼續在切走的位置繼續執行(保持狀態)

#什麽時候切換?
#比如,有兩個程序都在進行IO情況,在阻塞的時候就進行切換。
#切換和保存狀態我們適用關鍵字yeild # yeild切換出去 # 而切換進來有兩種方式con1.__next__()這種方式,con1.send(n) # 第一種方式能切換進來執行代碼,第二種方式可以傳遞參數進行交互 # yeild相當於return多了保存狀態的功能,下次還可以切換回來,繼續接著上次切換出去的地方執行

yeild實現協程

import time

def cumtom(name):
    print(%s準備吃包子 %name)
    time.sleep(1)
    while 1:
        count
=yield print(%s吃到第%d個包子 %(name,count)) def producter(): con1.__next__() con2.__next__() n=1 while 1: time.sleep(1) print(已經生產出來%d、%d個包子 %(n,n+1)) #通過send方法通知 con1.send(n) con2.send(n+1) n+=2 #cumtom函數裏面有yield,這裏傳遞參數,會創建一個生成器對象,(提前做了預處理)
con1=cumtom(cumtom1) con2=cumtom(cumtom2) producter()

gevent

# gevent
# gevent是一個著名的開發框架。Gevent是python的第三方庫,提供了比較完善的對協程的支持
# Gevent是一個基於libev的並發庫。它為各種並發和網絡相關的任務提供了整潔的API。
# Gevent的基本思想是:當遇到IO操作時,會自動寫換到其他gevent,再在適當的時間切回來繼續執行。這樣就減少了IO操作時的等待耗時,從而能夠提高硬件資源的利用率。

# gevent特點
# 1.基於libev的高效時間循環
# Libev是什麽?
# Libev是高性能事件循環/事件模型的網絡庫,並且包含大量新特性。它是繼lievent之後的一套全新網絡庫。它追求的目標:速度更快,bug更少,特性更多,體積更小。它和libevent很像,按照作者的介紹,可以作為libevent的替代者,能夠提供更高的性能,並且不需要復雜配置。
# 2.基於greenlet的輕量級執行單元
# 3.重用Python標準庫API內容(比如Events,Queues)
# 4.socket協同ssl
# 5.利用線程池或者c-cares 來執行DNS查詢
# 6.靈猴補丁能夠協同第三方庫
1.gevent中一個很大的改進就是將阻塞IO改為非阻塞IO;
2.比如gevent.socket.patch就是將項目中阻塞socket變為非阻塞;

  

greenlet/eventlet/gevent的關系

Greelent實現了一個比較易用(相比yeild)的協程切換的庫。但是greenlet沒有自己的調度過程,所以一般不會直接使用。
Eventlet在Greenlet的基礎上實現了自己的GreenThread,實際上就是greenlet類的擴展封裝,而與Greenlet的不同是,Eventlet實現了自己調度器稱為Hub,Hub類似於Tornado的IOLoop,是單實例的。
在Hub中有一個event loop,根據不同的事件來切換到對應的GreenThread。同時Eventlet還實現了一系列的補丁來使Python標準庫中的socket等等module來支持GreenThread的切換。
Eventlet的Hub可以被定制來實現自己調度過程。 Gevent基於libev和Greenlet。不同於Eventlet的用python實現的hub調度,Gevent通過Cython調用libev來實現一個高效的event loop調度循環。
同時類似於Eventlet,Gevent也有自己的monkey_patch,在打了補丁後,完全可以使用python線程的方式來無感知的使用協程,減少了開發成本。

gevent猴子補丁

猴子補丁monkey_patch,將標準庫中大部分的阻塞式調用替換成非阻塞的方式,包括socket、ssl、threading、select、httplib等。通過monkey.patch_xxx()來打補丁。
按照gevent文檔中的建議,應該將猴子補丁的代碼盡可能早的被調用,這樣可以避免一些奇怪的異常。 gevent實現了協程的創建、切換和調度,本身是同步的,而猴子補丁將gevent調用的阻塞庫變成非阻塞的,兩者配合實現了高性能的協程。

#優點:遇到IO操作自動切換
# import gevent
# import requests,time
#
# def get(url):
#     print(‘GET:%s‘ %url)
#     response=requests.get(url)
#     data=response.text
#     print(data)
#
#
# gevent.joinall([
#     gevent.spawn(get,‘http://python.jobbole.com/84301/‘),
#     gevent.spawn(get,‘https://www.cnblogs.com/xybaby/p/6337944.html‘),
#     # gevent.spawn(get,‘‘),
#     # gevent.spawn(get,‘‘)
# ])
#

greenlet(輕量級並發編程庫)

greenlet如何實現並發
1.greenlet是stackless python(支持微線程tasklet的CPython版本)的副產品。Tasklet以偽並發運行著(如果在單個或者很少的系統級線程內); 2.greenlet是一個原始的微線程的概念,沒有調度,可以稱為協程。所以green需要自己調度; 3.如果有阻塞調用,將greenlet主動切換出去。 greenlet與python線程關系 單個線程內可以運行任意哥greenlet微線程,不同線程之間不能切換greenlet。

  

#這裏的切換就更簡單了調用switch()就可以進行切換,而切換的發起端就是調用switch()的一端(先執行)
#缺點:手動切換
# import greenlet
#
#
# def test1():
#     print(1)
#     g2.switch()
#     print(3)
#     g2.switch()
#
#
# def test2():
#     print(2)
#     g1.switch()
#     print(4)
#
#
# g1=greenlet.greenlet(test1)
# g2=greenlet.greenlet(test2)
#
# g2.switch()

實現並發-協程gevent