進程池線程池與單程下實現並發
阿新 • • 發佈:2019-05-09
cti 識別不了 最小 gif cnblogs 支持 返回結果 block min
一、 socket並發(進程線程池鋪墊)
服務端:
import socket from threading import Thread """ 服務端: 1.固定的ip和port 2.24小時不間斷提供服務 3.支持高並發 """ server = socket.socket() server.bind((‘127.0.0.1‘,8080)) server.listen(5) # 半連接池 def communicate(conn): while True: try: data = conn.recv(1024) # 阻塞 if len(data) == 0:breakView Codeprint(data) conn.send(data.upper()) except ConnectionResetError: break conn.close() while True: conn,addr = server.accept() # 阻塞 print(addr) t = Thread(target=communicate,args=(conn,)) t.start()
客戶端:
import socket client = socket.socket() client.connect((‘127.0.0.1View Code‘,8080)) while True: info = input(‘>>>:‘).encode(‘utf-8‘) if len(info) == 0:continue client.send(info) data = client.recv(1024) print(data)
二 、 進程池線程池
如一中的socket並發,假如客戶端的數量呈萬級甚至百萬千萬級時,此時cup恐怕要冒煙了,那怎麽樣能解決同一時間的超大高並發呢?進程池和線程池能夠解決
說在前面:無論是開線程還是開進程其實都消耗資源,開線程消耗的資源比開進程的小。
池:
為了減緩計算機硬件的壓力,避免計算機硬件設備崩潰
雖然減輕了計算機硬件的壓力,但是一定程度上降低了持續的效率
進程池線程池:
為了限制開設的進程數和線程數,從而保證計算機硬件的安全
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import time import os # 示例化池對象 # 不知道參數的情況,默認是當前計算機cpu個數乘以5,也可以指定線程個數 pool = ProcessPoolExecutor(5) # 創建了一個池子,池子裏面有20個線程 def task(n): print(n,os.getpid()) time.sleep(2) return n**2 def call_back(n): print(‘我拿到了結果:%s‘%n.result()) """ 提交任務的方式 同步:提交任務之後,原地等待任務的返回結果,再繼續執行下一步代碼 異步:提交任務之後,不等待任務的返回結果(通過回調函數拿到返回結果並處理),直接執行下一步操作 """ # 回調函數:異步提交之後一旦任務有返回結果,自動交給另外一個去執行 if __name__ == ‘__main__‘: # pool.submit(task,1) 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(‘主‘)View Code
三 、 協程
學習協程前的鋪墊:
進程:資源單位(車間)
線程:最小執行單位,即CPU的執行單位(流水線)
協程:單線程下實現並發
並發:看上去像同時執行的就可以稱之為並發。
多道技術:
空間上的復用
時間上的復用
核心:切換+保存狀態
協程:完全就是高技術的人自己意淫出來的,但是沒想到還挺好用
通過代碼層面自己檢測 io 自己實現切換,讓操作系統誤以為你這個線程沒有 io
實現原理就是:通過代碼實現切換+保存狀態
運用範圍:單線程實現高並發
開多進程
多個進程下面再開多線程
多個線程下開協程
實現高並發
gevent 模塊的使用(genvet就是用來實現類似切換+保存效果)
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,‘egon‘) s2 = spawn(ha,‘echo‘) s1.join() s2.join() # heng(‘egon‘) # ha(‘kevin‘) print(‘主‘,time.time()-start)View Code
用 gevent 模塊實現網絡通信的單線程高並發
服務端
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()View Code
客戶端
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()View Code
四 、IO模型初識
上海張江第一帥元少對於 IO 模塊的理解:
https://www.cnblogs.com/Dominic-Ji/p/10806351.html
進程池線程池與單程下實現並發