python學習筆記——協程

協程是一種用戶態的輕量級線程

協程擁有自己的寄存器上下文和棧,能保留上一次調用時的狀態。每次過程衝入時,進入上一次離開時所處邏輯流的位置。

協程是串行工作,同一時間只能執行一個攜程,不需要加鎖。但是進行阻塞(Blocking)操作(如IO操作時)會阻塞掉整個程序。

通過協程在單線程裏實現併發效果。

適合做高併發處理。

yield關鍵字

send()

解決協程阻塞:

greenlet 模塊

gevent 模塊(基於greenlet模塊)

gevent.spawn()啓動一個協程

範例:單線程下併發執行一個函數

from urllib.request import urlopen
import gevent

def f(url):
    print('GET: %s' %url)
    resp = urlopen(url)
    data = resp.read()
    print('%d byte received form %s.'%(len(data),url))

#單線程下併發的執行一個下載任務
gevent.joinall([    #開啓了三個協程
    gevent.spawn(f,'https://www.python.org/'),
    gevent.spawn(f,'https://www.yahoo.com'),
    gevent.spawn(f,'https://github.com/'),
])

結果:

GET: https://www.python.org/
47410 byte received form https://www.python.org/.
GET: https://www.yahoo.com
465372 byte received form https://www.yahoo.com.
GET: https://github.com/
92691 byte received form https://github.com/.
範例:單線程下的多socket併發

server side

import gevent

from gevent import socket,monkey
monkey.patch_all() #monkey 將python中的很多變成非阻塞的形式

def server(port):
    s = socket.socket()
    s.bind(('0.0.0.0',port))
    s.listen(500)
    while True:
        cli,addr = s.accept()
        gevent.spawn(handle_request,cli) #啓動了一個協程,將cli客戶端穿了進來

def handle_request(s):
    try:
        while True:
            data = s.recv(1024)
            print('recv:',data)
            s.send(data)
            if not data: #沒有數據就斷開了
                s.shutdown(socket.SHUT_WR) #把客戶端銷燬
    except Exception as ex:
        print(ex)
    finally:
        s.close() #把跟這個客戶端的鏈接關掉

if __name__ =='__main__':
    server(8001) #啓動在8001端口
client side

import socket

HOST = 'localhost'
PORT = 8001
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((HOST,PORT))
while True:
    msg = bytes(input('>>:'),encoding='utf8')
    s.sendall(msg)
    data = s.recv(1024)

    print('Reveived',repr(data))

s.close()






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章