1. 程式人生 > >進程池線程池與單程下實現並發

進程池線程池與單程下實現並發

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:break
print(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()
View Code

客戶端:

技術分享圖片
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)
View Code

二 、 進程池線程池

如一中的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

進程池線程池與單程下實現並發