1. 程式人生 > >並發編程——進程池線程池、協程、IO模型

並發編程——進程池線程池、協程、IO模型

acc args 連接 所有 作用 art 滿足 nbsp 怎麽

1、socket 服務端實現高並發 網絡編程服務端需要滿足的要求:

①固定的IP和port

②24H提供服務

③能實現並發

技術分享圖片
# socket實現並發
# seerver
import socket
from threading import Thread
server = socket.socket()
server.bind((‘127.0.0.1‘,8080))
server.listen(5)


def communicate():
    # 通訊循環
	while True:
		try:
			# 接收數據
			data = conn.recv(1024)
            if
len(data) == 0:break print(data) conn.send(data.upper()) except ConnectionResetError: break conn.close() #連接循環 while TRUE: conn addr = server.accept() # 開啟線程 t = Thread(target = communicate,args=(conn,)) t.start()
server 技術分享圖片
# cliet 
import
socket client = socket.socket() client.connect((‘127.0.0.1‘,8080)) # 通訊循環 while True: info = input(‘>>>‘).encode(‘utf-8‘) if len(info) == 0:continue client.send(info) data = client.recv(1024) print(data) conn.close() #連接循環 while TRUE: conn addr = server.accept() # 開啟線程
t = Thread(target = communicate,args=(conn,)) t.start()
client

2、進程池和線程池

進程池和線程池介紹

進程池和線程池都是為了減輕硬件負擔,保證程序的運行,相對減少的運行速度

1 模塊導入:
	from concurrent.futuers import ThreadPoolExecutor,ProcessPoolExecutor
2 實例化:
#在不知道參數的情況下,默認為當前計算機的cpu個數*5
	線程池:pool = ThreadpoolExecutor(N)
    進程池:pool = ProcesspoolExecutor(N)
3 提交任務
	pool.submit()
  提交任務的兩種方式:
	① 同步:提交任務後,原地等待任務的返回結果,再執行下一步代碼
	② 異步:提交任務後,不等待任務返回結果(通過回調函數拿到返回值),直接進下一步代碼
4 回調函數:add_done_call()
	異步提交後一旦任務有返回結果自定交給另外一個去執行
5 pool.shutdown:
    關閉池子,並且等待池子中所有的任務運行完畢

例子

技術分享圖片
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time
import os


pool = ProcessPoolExecutor(5)
# pool = ThreadPoolExecutor(5)

def task(n):
    print(n,os.getpid())
    time.sleep(2)
    return n**2

def call_back(n):
    print(‘拿到結果:%s‘%n.result())

if __name__ == ‘__main__‘:
    t_list = []
    for i in range(20):
        # 回調函數,異步提交任務
        future = pool.submit(task,i).add_done_callback(call_back)
        t_list.append(future)
        pool.shutdown()
        for p in t_list:
            print(">>>",p.result())
    print(‘主‘)


進程池和線程池使用

3、協程

1、進程:資源單位

2、線程:執行單位

3、協程:單線程下實現並

4、協程是技術人員虛擬出來的的概念,對於操作系統並不存在

核心:切換+保存狀態 作用就是將單線程的效率提升到最高,多進程下開多線程,多線程下用協程,實現高並發

優點:協程切換開銷小,單線程內實現並發的效果,最大限度的利用cpu

缺點:無法利用多核,一旦阻塞整個線程就會阻塞

怎麽使用

1 導入gevent模塊
g1=gevent.spawn(func,1,,2,3,x=4,y=5)創建一個協程對象g1,spawn括號內第一個參數是函數名,如eat,後面可以有多個參數,可以是位置實參或關鍵字實參,都是傳給函數eat的
2 g1.join() #等待g1結束
3 g1.value#拿到func1的返回值

協程實現高並發:

技術分享圖片
from gevent import monkey;monkey.patch_all()
import socket
from gevent import spawn

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()

server 技術分享圖片
import socket
from threading import Thread,current_thread

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()


    while True:
        conn,addr = server.accept()
        spawn(communicate,conn)

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

4 IO 模型

① 阻塞IO

② 非阻塞IO:非阻塞IO(服務端通信針對accept用s.setblocking(False)加異常捕獲,cpu占用率過高)

③ IO多路復用:

在只檢測一個套接字的情況下,他的效率連阻塞IO都比不上。因為select這個中間人增加了環節。

但是在檢測多個套接字的情況下,就能省去wait for data過程

④ 異步IO

並發編程——進程池線程池、協程、IO模型