一、程序池和執行緒池
當被操作物件數目不大時,我們可以手動建立幾個程序和執行緒,十幾個幾十個還好,但是如果有上百個上千個。手動操作麻煩而且電腦硬體跟不上,可以會崩潰,此時程序池、執行緒池的功效就能發揮了。我們可以通過維護乙個程序池、執行緒池來控制程序數目和執行緒數目。在保證計算機硬體安全的情況下最大限度的利用計算機,池其實是降低了程式的執行效率,但是保證了計算機硬體的安全。
注意點:在使用程序池、執行緒池,pool可以提供指定數量的程序,執行緒,供使用者呼叫,當有新的請求提交到pool中時,如果池還沒有滿,那麼就會建立乙個新的程序,執行緒用來執行該請求,但如果池中的程序,執行緒數量已經達到規定的最大值,那麼該請求就會等待,直到池中有程序,執行緒結束,就重新使用程序池、執行緒池中的程序,執行緒。
池子中建立的程序/執行緒建立一次就不會再建立了,至始至終都是使用最初的那幾個,這樣的話節省了反覆開闢程序/執行緒的資源(******)
主要方法:
pool.submit(task,1) #朝池子中提交任務 非同步提交 task是函式,1是task的引數
pool.shutdown() #
關閉池子 等待池子中所有任務執行完畢之後才會往下執行**
執行緒池和程序池建立的方法一樣只是匯入的模組不一樣
**函式add_done_callback,我們可以把耗時間(io操作)的任務放在程序池中,然後指定**函式(主程序負責執行),這樣主程序在執行**函式時就省去了io的過程,直接拿到的是任務的結果。
非同步**機制:當非同步提交的任務有返回結果之後,會自動觸發**函式的執行。
from concurrent.futures importthreadpoolexecutor,processpoolexecutor
import
time
importos#
pool = threadpoolexecutor(5) 建立執行緒池 # 括號內可以傳引數指定執行緒池內的執行緒個數
也可以不傳 不傳預設是當前所在計算機的cpu個數乘5
pool = processpoolexecutor() 建立程序池 #
預設是當前計算機cpu的個數
deftask(n):
print(n,os.getpid()) #
檢視當前程序號
time.sleep(2)
return n**2
defcall_back(n):
print('
拿到了非同步提交任務的返回結果:
',n.result()) #submit提交任務返回值,需要result才能獲取結果
"""非同步**機制:當非同步提交的任務有返回結果之後,會自動觸發**函式的執行
"""if
__name__ == '
__main__':
for i in range(20):
pool.submit(task,i).add_done_callback(call_back)
#提交任務的時候 繫結乙個**函式 一旦該任務有結果 立刻執行對於的**函式
#submit提交任務task函式,當有返回值時,立刻把返回值傳入**函式
二、協程
協程就是單執行緒下實現併發 ,協程:完全是程式設計師自己想出來的乙個名詞
程式設計師通過自己**檢測程式中的io操作,一旦遇到io自己通過**切換,給作業系統的感覺是你這個執行緒沒有任何的io,從而保證程式在執行態和就緒態來回切換,提公升**的執行效率。
切換+儲存狀態就一定能夠提公升效率嗎???
當你的任務是io密集型的情況下 會提公升效率
當你的任務是計算密集型時 會降低效率
spawn會自動幫你檢測任務有沒有i/o,碰到i/o就切換
from gevent import monkey;monkey.patch_all() #由於該模組經常被使用 所以建議寫成一行
from gevent import
spawn
import
time
"""注意gevent模組沒辦法自動識別time.sleep等io情況
需要你手動再配置乙個引數 monkey
"""def
heng():
print("哼"
) time.sleep(2)
print('哼'
)def
ha():
print('哈'
) time.sleep(3)
print('哈'
)def
heiheihei():
print('
嘿嘿嘿'
) time.sleep(5)
print('
嘿嘿嘿'
)start =time.time()
g1 =spawn(heng)
g2 = spawn(ha) #
spawn會檢測所有的任務
g3 =spawn(heiheihei)
g1.join()
g2.join()
g3.join()
print(time.time() -start)#結果
哼哈嘿嘿嘿哼
哈嘿嘿嘿
5.012551546096802
三、tcp單執行緒實現併發
服務端
from gevent importmonkey;monkey.patch_all()
import
socket
from gevent import
spawn
server =socket.socket()
server.bind((
'127.0.0.1
',8080))
server.listen(5)
deftalk(conn):
while
true:
try:
data = conn.recv(1024)
if len(data) == 0:break
print(data.decode('
utf-8'))
conn.send(data.upper())
except
connectionreseterror as e:
(e)
break
conn.close()
defserver1():
while
true:
conn, addr =server.accept()
spawn(talk,conn)
if__name__ == '
__main__':
g1 =spawn(server1)
g1.join()
客戶端 實現400個執行緒,模擬400個使用者
importsocket
from threading import
thread,current_thread
defclient():
client =socket.socket()
client.connect((
'127.0.0.1
',8080))
n =0
while
true:
data = '
%s %s
'%(current_thread().name,n)
client.send(data.encode(
'utf-8'))
res = client.recv(1024)
print(res.decode('
utf-8'))
n += 1
for i in range(400):
t = thread(target=client)
t.start()
併發程式設計 執行緒池程序池協程
1.socket服務端實現併發 現在回來想網路程式設計服務端需要滿足哪幾點需求 2.程序池執行緒池介紹 執行緒不可能無限制的開下去,總要消耗和占用資源 程序池執行緒池概念 硬體有極限,為了減輕硬體壓力,所以有了池的概念 注意協程這個概念完全是程式設計師自己想出來的東西,它對於作業系統來說根本不存在。...
單執行緒記憶體池
1 單執行緒記憶體池 記憶體池的基本思想是大塊向系統申請記憶體,內部切割為小塊,內部 cache 之後有選擇的分配,不夠的時候繼續向系統大塊申請記憶體,示例 如下 struct tm memblock class tm pool void tm pool newobj tm bufunit head...
執行緒佇列,執行緒池,協程
執行緒的queue,類似於程序 作用也是類似,queue n 規範放入值的數量 這個和之前一樣是為了實現先進先出 import queue q queue.queue 2 括號內可加入數字規範放入值的數量,不加則不會規範 q.put 123 q.put qweqwe q.put 111 print ...