37 協程

協程

進程:資源單位程序員

線程:執行單位web

協程:單線程下實現併發(可以在多個任務之間切換和保存狀態來節省IO)多線程

多道技術: 併發

  空間上的複用 異步

  時間上的複用socket

核心:切換+保存狀態ide

注意:高併發

  操做系統的切換+保存狀態是針對多個線程,spa

  想在單個線程下本身手動實現操做系統的切換+保存狀態的功能,協程產生操作系統

  因爲協程是程序員本身想出來並實現,它對於操做系統來講根本不存在。操做系統只知道進程和線程。

  須要注意的是:並非單個線程下實現切換+保存狀態就能提高效率,可能沒有遇到io也切,那反而會下降效率

    任務是計算密集型,反而會下降效率

    任務是IO密集型,會提高效率

將單個線程的效率提高到最高,多進程下開多線程,多線程下用協程>>> 實現高併發!!! 

  1)yield可以實現保存上次運行狀態,可是沒法識別io

# 串行執行
import time


def func1():
    for i in range(10000000):
        i + 1


def func2():
    for i in range(10000000):
        i + 1


start = time.time()
func1()
func2()
stop = time.time()
print(stop - start)




# 基於yield併發執行
import time


def func1():
    while True:
        10000000 + 1
        yield


def func2():
    g = func1()
    for i in range(10000000):
        time.sleep(100)  # 模擬IO,yield並不會捕捉到並自動切換
        i + 1
        next(g)


start = time.time()
func2()
stop = time.time()
print(stop - start)
切換➕保存狀態

2)單線程下實現併發

若是你可以本身經過代碼層面監測你本身的io行爲
而且經過代碼實現切換+保存狀態
單線程實現高併發
# ---------------服務端---------------------
from gevent import monkey; monkey.patch_all()
from gevent import spawn
import socket


def communicate(conn):
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0: break
            print(data.decode('utf-8'))
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()


def server():
    server = socket.socket()
    server.bind(('127.0.0.1', 8080))
    server.listen(5)
    while True:
        conn, addr = server.accept()
        spawn(communicate, conn)


if __name__ == '__main__':
    s1 = spawn(server)
    s1.join()



# ---------------客戶端---------------------
from threading import Thread, current_thread
import socket


def client():
    client = socket.socket()
    client.connect(('127.0.0.1', 8080))
    n = 1
    while True:
        data = '%s %s' % (current_thread().name, n)
        n += 1
        client.send(data.encode('utf-8'))
        info = client.recv(1024)
        print(info)


if __name__ == '__main__':
    for i in range(500):
        t = Thread(target=client)
        t.start()

3)gevent模塊的使用

  spawn:幫你管理任務的對象

  gevent模塊不能識別它自己之外的全部的IO行爲,可是它內部封裝了一個模塊,可以幫助咱們識別全部的IO行爲

 

from gevent import monkey; 
monkey.patch_all()  # 監測代碼中全部io行爲
from gevent import spawn
# gevent自己識別不了time.sleep等不屬於該模塊內的io操做
import time


def heng(name):
    print('%s 哼' % name)
    time.sleep(2)
    print('%s 哼' % name)


def ha(name):
    print('%s 哈' % name)
    time.sleep(3)
    print('%s 哈' % name)


start = time.time()
s1 = spawn(heng, 'Tom')
s2 = spawn(ha, 'Bob')

s1.join()
s2.join()
# heng('Tom')
# ha('Bob')

print('', time.time() - start)

 4)協程實現服務端客戶端通訊:socket併發

# 服務端
from gevent import monkey;monkey.patch_all()
from socket import *   # !!!後
from gevent import spawn


def communicate(conn):
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0: break
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()
    

def server(ip, port, backlog=5):
    server = socket(AF_INET, SOCK_STREAM)
    server.bind((ip, port))
    server.listen(backlog)

    while True:  # 連接循環
        conn, client_addr = server.accept()
        print(client_addr)

        # 通訊
        spawn(communicate,conn)


if __name__ == '__main__':
    g1=spawn(server,'127.0.0.1',8080)
    g1.join()

    
# 客戶端
from threading import Thread, current_thread
from socket import *


def client():
    client = socket(AF_INET, SOCK_STREAM)
    client.connect(('127.0.0.1', 8080))

    n = 0
    while True:
        msg = '%s say hello %s' % (current_thread().name, n)
        n += 1
        client.send(msg.encode('utf-8'))
        data = client.recv(1024)
        print(data.decode('utf-8'))


if __name__ == '__main__':
    for i in range(500):
        t = Thread(target=client)
        t.start()

5)IO模型 

阻塞IO  Blocking I/O非阻塞IO  服務端通訊針對accept用s.setblocking(False)加異常捕獲,cpu佔用率太高IO多路複用 multiplexing I/O  在只檢測一個套接字的狀況下,他的效率連阻塞IO都比不上。由於select這個中間人增長了環節。  可是在檢測多個套接字的狀況下,就能省去wait for data過程異步IO  Asynchronous I/O
相關文章
相關標籤/搜索