目錄
- 一、什么是協程
- 二、為什么要有協程
- 三、協程的優缺點
- 四、如何實現協程
-
五、Gevent模塊
- 5.1 模塊的安裝
- 5.2 用法介紹
- 5.3 代碼實例
- 六、gevent之應用
一、什么是協程
協程: 就是 單線程 下 實現并發
協程概念本質是程序員抽象出來的,是人為的控制通過程序的IO去進行切換任務的執行
并發:任務切換+保存狀態
二、為什么要有協程
自己控制切換要比操作系統切換快的多.降低了單個線程的io堵塞時間,也就是實現了單線程下效率最高.
三、協程的優缺點
-
優點:
自己控制切換要比操作系統切換快的多
-
缺點:
- 需要自己要檢測所有的io,但凡有一個阻塞整體都跟著阻塞.
- 無法利用多核優勢.
四、如何實現協程
其實協程的本質就是在單線程下實現并發,也就是通過生成器
yield
和
next
進行迭代生成器,實現切換任務和保存任務。
在Python中我們需要使用gevnet模塊來實現協程
五、Gevent模塊
Gevent 是一個第三方庫,可以輕松通過gevent實現并發同步或異步編程,在gevent中用到的主要模式是Greenlet,它是以C擴展模塊形式接入Python的輕量級協程。 Greenlet全部運行在主程序操作系統進程的內部,但它們被協作式地調度。
5.1 模塊的安裝
安裝:
pip3 install gevent
5.2 用法介紹
g1=gevent.spawn(func,1,,2,3,x=4,y=5)
:創建一個協程對象g1,spawn括號內第一個參數是函數名,如eat,后面可以有多個參數,可以是位置實參或關鍵字實參,都是傳給函數eat的
g2=gevent.spawn(func2)
g1.join()
:等待g1結束
g2.join()
:等待g2結束
上述兩步合作一步:
gevent.joinall([g1,g2])
g1.value
:拿到func1的返回值
5.3 代碼實例
通過 from gevent import monkey;
monkey.patch_all() 去補丁,捕獲所以IO
from gevent import monkey;monkey.patch_all()
必須放到被打補丁者的前面,如time,socket模塊之前。
import time
from gevent import monkey;monkey.patch_all()
'''打了一個補丁,它可以實現捕獲非gevent的所有io'''
import gevent
def eat():
print('eat 1')
time.sleep(2)
# gevent.sleep(2) # 可以這樣單獨捕捉阻塞,但是太麻煩,所以直接打補丁,捕捉運行期間的全部IO
print('eat 2')
def play():
print('play 1')
# 瘋狂的計算呢沒有io
time.sleep(3)
# gevent.sleep(3) # 可以這樣單獨捕捉阻塞,但是太麻煩,所以直接打補丁,捕捉運行期間的全部IO
print('play 2')
'''
gevent實現協程的模塊,它可以捕獲單線程中的io并去切換任務
'''
if __name__ == '__main__':
# 把本該串行的代碼通過協程完成單線程并行
start = time.time()
g1 = gevent.spawn(eat) # 創建一個協程對象
g2 = gevent.spawn(play)
# g1.join() # 等待回收協程對象
# g2.join()
gevent.joinall([g1,g2]) # 把上面兩步并一步
end = time.time()
print(end-start)
六、gevent之應用
通過gevent實現單線程下的socket并發
注意: from gevent import monkey;monkey.patch_all()一定要放到導入socket模塊之前,否則gevent無法識別socket的阻塞。
服務器
import socket
from gevent import monkey; monkey.patch_all() # 打補丁
import gevent
'''
基于協程的socket通訊
協程:單線程下實現并發
'''
def connec_interface(conn,addr):
while 1:
try:
data = conn.recv(1024)
if not data:
break
print(f"來自{addr}的消息:",data.decode("utf8"))
data = input(f"與{addr}聊天")
conn.send(data.encode("utf8"))
except:
break
if __name__ == '__main__':
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(("127.0.0.1",8080))
server.listen(5)
while 1:
print("等待連接。。。")
conn,addr = server.accept()
print("連接成功")
gevent.spawn(connec_interface, conn, addr) # 創建一個協程對象
客戶端
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(("127.0.0.1",8080))
while 1:
msg = input("請輸入內容")
client.send(msg.encode("utf8"))
data = client.recv(1024)
if not data:
break
print(data.decode("utf8"))
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
