併發程式設計之協程

2022-04-11 16:12:42 字數 3624 閱讀 2793

協程:是單執行緒下的併發,一句話說明什麼是執行緒:協程是一種使用者態的輕量級執行緒,即協程是由使用者程式自己控制排程的。

對比作業系統控制線程的切換,使用者在單執行緒內控制協程的切換

優點:

#

1. 協程的切換開銷更小,屬於程式級別的切換,作業系統完全感知不到,因而更加輕量級

#2. 單執行緒內就可以實現併發的效果,最大限度地利用cpu

缺點:

#

1. 協程的本質是單執行緒下,無法利用多核,可以是乙個程式開啟多個程序,每個程序內開啟多個執行緒,每個執行緒內開啟協程

#2. 協程指的是單個執行緒,因而一旦協程出現阻塞,將會阻塞整個執行緒

總結協程特點:

1、必須在只有乙個單執行緒裡實現併發

2、修改共享資料不需加鎖

3、使用者程式裡自己儲存多個控制流的上下文棧

4、附加:乙個協程遇到io操作自動切換到其它協程(如何實現檢測io,yield、greenlet都無法實現,就用到了gevent模組(select機制))

協程的實現:

import

time

deftask():

while

true:

print("

task1")

time.sleep(4)

yield 1

deftask2():

g =task()

while

true:

try:

print("

task2")

next(g)

except

exception:

print("

任務完成")

break

task2()

應用場景:

tcp 多客戶端實現方式

1.來乙個客戶端就來乙個程序 資源消耗較大

2.來乙個客戶端就來乙個執行緒 也不能無限開

3.用程序池 或 執行緒池 還是乙個執行緒或程序只能維護乙個連線

4.協程 乙個執行緒就可以處理多個客戶端 遇到io就切到另乙個

import

greenlet

import

time

deftask1():

print("

task1 1")

time.sleep(2)

g2.switch()

print("

task1 2")

g2.switch()

deftask2():

print("

task2 1")

g1.switch()

print("

task2 2")

g1 =greenlet.greenlet(task1)

g2 =greenlet.greenlet(task2)

g1.switch()

#1.例項化greenlet得到乙個物件 傳入要執行的任務

#至少需要兩個任務

#2.先讓某個任務執行起來 使用物件呼叫switch

#3.在任務的執行過程中 手動呼叫switch來切換

greenlet只是提供了一種比generator更加便捷的切換方式,當切到乙個任務執行時如果遇到io,那就原地阻塞,仍然是沒有解決遇到io自動切換來提公升效率的問題。

單執行緒裡的多個任務的**通常會既有計算操作又有阻塞操作,我們完全可以在執行任務1時遇到阻塞,就利用阻塞的時間去執行任務2。。。。如此,才能提高效率,這就用到了gevent模組。

gevent 是乙個第三方庫,可以輕鬆通過gevent實現併發同步或非同步程式設計,在gevent中用到的主要模式是greenlet, 它是以c擴充套件模組形式接入python的輕量級協程。 greenlet全部執行在主程式作業系統程序的內部,但它們被協作式地排程。

from gevent import

monkey

monkey.patch_all()

import

gevent

import

time

defeat():

print('

eat food 1')

time.sleep(2)

#gevent.sleep(1)

print('

eat food 2')

defplay():

print('

play 1')

time.sleep(1)

#gevent.sleep(1)

print('

play 2')

g1=gevent.spawn(eat)

g2=gevent.spawn(play)

#g1.join()

#g2.join()

gevent.joinall([g1,g2])

print('主'

)#1.spawn函式傳入你的任務

#2.呼叫join 去開啟任務

#3.檢測io操作需要打monkey補丁 就是乙個函式 在程式最開始的地方呼叫它

練習:使用協程完成tcp套接字程式設計 支援多客戶端同時訪問

import

gevent

from gevent import

monkey

monkey.patch_all()

import

socket

server =socket.socket()

#重用埠

server.setsockopt(socket.sol_socket,socket.so_reuseaddr,1)

server.bind((

"127.0.0.1

",9999))

server.listen(5)

defdata_handler(conn):

print("

乙個新連線..")

while

true:

data = conn.recv(1024)

conn.send(data.upper())

while

true:

conn,addr =server.accept()

#切到處理資料的任務去執行

gevent.spawn(data_handler,conn)

伺服器

import

socket

c =socket.socket()

c.connect((

"127.0.0.1

",9999))

while

true:

msg = input("

>>>:")

ifnot msg:continue

c.send(msg.encode(

"utf-8"))

data = c.recv(1024)

print(data.decode("

utf-8

"))

客戶端

併發程式設計之 協程

程序 資源單位 執行緒 執行單位 協程 單執行緒下實現併發 併發 切換 儲存狀態 程式設計師自己通過 自己檢測程式中的io 一旦遇到了io自己通過 切換 給作業系統的感覺就是你這個執行緒沒有任何的io 從而提公升 的執行效率 切換 儲存狀態一定能夠提公升效率嗎?1.當任務是io密集型的情況下 提公升...

Python 之併發程式設計之協程

def gen for i in range 10 yield i 初始化生成七函式 返回生成器物件 簡稱生成器 mygen gen for i in mygen print i 1 用協程改寫成生產者消費者 def producer for i in range 100 yield i def c...

併發程式設計 協程

一 協程介紹 協程 是單執行緒下的併發,又稱微執行緒,纖程。英文名coroutine。一句話說明什麼是執行緒 協程是一種使用者態的輕量級執行緒,即協程是由使用者程式自己控制排程的。需要強調的是 對比作業系統控制線程的切換,使用者在單執行緒內控制協程的切換 優點如下 缺點如下 總結 必須在只有乙個單執...