並發編程——進程池線程池、協程、IO模型
阿新 • • 發佈:2019-05-09
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) ifserverlen(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()
# cliet importclientsocket 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()
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模型