天天看點

python并發程式設計之協程1、協程2、 驗證切換是否就一定提升效率2、 gevent子產品(了解)3、 協程實作TCP服務端的并發

1、協程

程序:資源機關

線程:執行機關

協程:這個概念完全是程式員自己意淫出來的 根本不存在

協程是單線程下實作并發
	我們程式員自己再代碼層面上檢測我們所有的IO操作
	一旦遇到IO了 我們在代碼級别完成切換
	這樣給CPU的感覺是你這個程式一直在運作 沒有IO
	進而提升程式的運作效率
           

多道技術

切換+儲存狀态
	CPU兩種切換
	1.程式遇到IO
	2.程式長時間占用
           

TCP服務端

accept
	recv
           

代碼如何做到

切換+儲存狀态
           

切換

切換不一定是提升效率 也有可能是降低效率
	IO切	提升
	沒有IO切 降低
           

儲存狀态

儲存上一次我執行的狀态 下一次來接着上一次的操作繼續往後執行
	yield
           

“”"

2、 驗證切換是否就一定提升效率

import time

# 串行執行計算密集型的任務   1.2372429370880127
def func1():
    for i in range(10000000):
        i + 1

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

start_time = time.time()
func1()
func2()
print(time.time() - start_time)

切換 + yield  2.1247239112854004
import time


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


def func2():
    g = func1()  # 先初始化出生成器
    for i in range(10000000):
        i + 1
        next(g)

start_time = time.time()
func2()
print(time.time() - start_time)
           

2、 gevent子產品(了解)

安裝

pip3 install gevent
           
from gevent import monkey;monkey.patch_all()
import time
from gevent import spawn

"""
gevent子產品本身無法檢測常見的一些io操作
在使用的時候需要你額外的導入一句話
from gevent import monkey
monkey.patch_all()
又由于上面的兩句話在使用gevent子產品的時候是肯定要導入的
是以還支援簡寫
from gevent import monkey;monkey.patch_all()
"""


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


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

def heiheihei():
    print('heiheihei')
    time.sleep(5)
    print('heiheihei')


start_time = time.time()
g1 = spawn(heng)
g2 = spawn(ha)
g3 = spawn(heiheihei)
g1.join()
g2.join()  # 等待被檢測的任務執行完畢 再往後繼續執行
g3.join()
# heng()
# ha()
# print(time.time() - start_time)  # 5.005702018737793
print(time.time() - start_time)  # 3.004199981689453   5.005439043045044
           

3、 協程實作TCP服務端的并發

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


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


def server(ip, port):
    server = socket.socket()
    server.bind((ip, port))
    server.listen(5)
    while True:
        conn, addr = server.accept()
        spawn(communication, conn)


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

    
# 用戶端
from threading import Thread, current_thread
import socket


def x_client():
    client = socket.socket()
    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=x_client)
        t.start()
           

總結

"""
理想狀态:
	我們可以通過
	多程序下面開設多線程
	多線程下面再開設協程式
	進而使我們的程式執行效率提升
"""