網路程式設計之 協程

2021-10-10 08:25:59 字數 4762 閱讀 6513

協程,又稱微執行緒,纖程。英文名coroutine。一句話說明什麼是執行緒:協程是一種使用者態的輕量級執行緒

協程擁有自己的暫存器上下文和棧。協程排程切換時,將暫存器上下文和棧儲存到其他地方,在切回來的時候,恢復先前儲存的暫存器上下文和棧。因此:協程能保留上一次呼叫時的狀態(即所有區域性狀態的乙個特定組合),每次過程重入時,就相當於進入上一次呼叫的狀態,換種說法:進入上一次離開時所處邏輯流的位置。

優點:

方便切換控制流,簡化程式設計模型

高併發+高擴充套件性+低成本:乙個cpu支援上萬的協程都不是問題。

缺點:

符合什麼條件就能稱之為協程:

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

修改共享資料不需加鎖

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

乙個協程遇到io操作自動切換到其它協程

greenlet是乙個用c實現的協程模組,相比與python自帶的yield,它可以使你在任意函式之間隨意切換,而不需把這個函式先宣告為generator

from greenlet import greenlet

deftest1()

:print(12

) gr2.switch(

)print(34

) gr2.switch(

)def

test2()

:print(56

) gr1.switch(

)print(78

) gr1.switch(

)gr1 = greenlet(test1)

# 生成乙個協程

gr2 = greenlet(test2)

gr1.switch(

)# 輸出結果:

1256

3478

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

2.1 協程間自動切換

import gevent

deffoo()

:print

('runnig foo'

) gevent.sleep(2)

print

('explicit running in foo again'

)def

bar():

print

('running bar'

) gevent.sleep(1)

print

('explicit running in bar again'

)def

fun():

print

('running fun'

) gevent.sleep(0)

# gevent.sleep()觸發切換

print

('explicit running in fun again'

)gevent.joinall(

[ gevent.spawn(foo)

, gevent.spawn(bar)

, gevent.spawn(fun),]

)# 列表形式,產生3個協程,實現協程之間自動切換

# 輸出:

runnig foo

running bar

running fun

explicit running in fun again

explicit running in bar again

explicit running in foo again

2.2 同步與非同步的效能區別

非同步遇到io阻塞時會自動切換任務

from urllib import request

import gevent,time

from gevent import monkey

monkey.patch_all(

)# 預設urllib無法與gevent協同,需要打個補丁,將當前程式所有i/o操作打標記

deffun

(url)

:print

('get: %s'

% url)

req = request.urlopen(url)

data = req.read(

)print

('%d bytes receied from %s.'%(

len(data)

, url)

)urls =

['',''

,'']time_start = time.time(

)for url in urls:

fun(url)

print

('同步cost'

, time.time(

)- time_start)

async_time_start = time.time(

)gevent.joinall(

[ gevent.spawn(fun,

''),

gevent.spawn(fun,

''),

gevent.spawn(fun,

''),

])print

("非同步cost"

,time.time(

)- async_time_start)

2.3 實現單執行緒下的多socket併發

server端

import socket

import gevent

from gevent import monkey

monkey.patch_all(

)def

server

(port)

: ser = socket.socket(

) ser.bind(

('localhost'

, port)

) ser.listen(

1024

)while

true

: conn, addr = ser.accept(

) gevent.spawn(handle_request, conn)

defhandle_request

(conn)

:try

:while

true

: data = conn.recv(

1024

)print

('rece: '

, data)

conn.send(data.upper())

ifnot data:

conn.shutdown(socket.shut_wr)

except exception as ex:

print

(ex)

finally

: conn.close(

)if __name__ ==

'__main__'

: server(

6666

)

client端

#單次連線

import socket

host =

'localhost'

port =

6666

cli = socket.socket(

)cli.connect(

(host, port)

)while

true

: msg =

input

('>>: '

).strip(

).encode(

'utf-8')if

len(msg)==0

:continue

cli.send(msg)

data = cli.recv(

1024

)print

(data.decode(

'utf-8'))

# 併發

import socket

import threading

host =

'localhost'

port =

6666

defsock_conn()

: client = socket.socket(

) client.connect(

(host, port)

) client.send(

("hello %s"

%count)

.encode(

"utf-8"))

data = client.recv(

1024

)print

("[%s]recv from server:"

% threading.get_ident(

),data.decode())

#結果 client.close(

)for i in

range

(100):

t = threading.thread(target=sock_conn)

t.start(

)

網路程式設計之協程 gevent模組

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

併發程式設計之協程

協程 是單執行緒下的併發,一句話說明什麼是執行緒 協程是一種使用者態的輕量級執行緒,即協程是由使用者程式自己控制排程的。對比作業系統控制線程的切換,使用者在單執行緒內控制協程的切換 優點 1.協程的切換開銷更小,屬於程式級別的切換,作業系統完全感知不到,因而更加輕量級 2.單執行緒內就可以實現併發的...

併發程式設計之 協程

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