Python基础-多线程与多进程
一,線程與進程之間的關(guān)系:(從知乎上看到的)
一個必須知道的事實:執(zhí)行一段程序代碼,實現(xiàn)一個功能的過程介紹 ,當?shù)玫紺PU的時候,相關(guān)的資源必須也已經(jīng)就位,就是顯卡啊,GPS啊什么的必須就位,然后CPU開始執(zhí)行。這里除了CPU以外所有的就構(gòu)成了這個程序的執(zhí)行環(huán)境,也就是我們所定義的程序上下文。當這個程序執(zhí)行完了,或者分配給他的CPU執(zhí)行時間用完了,那它就要被切換出去,等待下一次CPU的臨幸。在被切換出去的最后一步工作就是保存程序上下文,因為這個是下次他被CPU臨幸的運行環(huán)境,必須保存。
串聯(lián)起來的事實:前面講過在CPU看來所有的任務(wù)都是一個一個的輪流執(zhí)行的,具體的輪流方法就是:先加載程序A的上下文,然后開始執(zhí)行A,保存程序A的上下文,調(diào)入下一個要執(zhí)行的程序B的程序上下文,然后開始執(zhí)行B,保存程序B的上下文。。。。
========= 重要的東西出現(xiàn)了========
進程和線程就是這樣的背景出來的,兩個名詞不過是對應(yīng)的CPU時間段的描述,名詞就是這樣的功能。
- 進程就是包換上下文切換的程序執(zhí)行時間總和 = CPU加載上下文+CPU執(zhí)行+CPU保存上下文
線程是什么呢?
進程的顆粒度太大,每次都要有上下的調(diào)入,保存,調(diào)出。如果我們把進程比喻為一個運行在電腦上的軟件,那么一個軟件的執(zhí)行不可能是一條邏輯執(zhí)行的,必定有多個分支和多個程序段,就好比要實現(xiàn)程序A,實際分成 a,b,c等多個塊組合而成。那么這里具體的執(zhí)行就可能變成:
程序A得到CPU =》CPU加載上下文,開始執(zhí)行程序A的a小段,然后執(zhí)行A的b小段,然后再執(zhí)行A的c小段,最后CPU保存A的上下文。
這里a,b,c的執(zhí)行是共享了A的上下文,CPU在執(zhí)行的時候沒有進行上下文切換的。這里的a,b,c就是線程,也就是說線程是共享了進程的上下文環(huán)境,的更為細小的CPU時間段。
到此全文結(jié)束,再一個總結(jié):
進程和線程都是一個時間段的描述,是CPU工作時間段的描述,不過是顆粒大小不同,一個進程中包含了多個線程,在一個時間段內(nèi),只能有一個線程占用cpu,cpu不能同時執(zhí)行多個任務(wù),只不過cpu運行速度太快,我們感知不到,就以為,線程可以同時執(zhí)行,對于多核cpu,實際也同一個時間段也只有一個cpu在工作
import threading import time def axb(name):
time.sleep(1)
print(name)
for i in range(10):
t=threading.Thread(target=axb,args=(i,)) ##args 定義的是一個元組,必須加逗號,才能識別為元組
t.start() print('game over')
三,線程等待
線程等待,多線程在運行的時候,每個線程都是獨立運行的,不受其他的線程干擾,如果想在哪個線程運行完之后,再做其他操作的話,就得等待它完成,那怎么等待呢,使用join,等待線程結(jié)束
import threading
import time
def run():
print('qqq')
time.sleep(1)
print('done!')
lis = []
for i in range(5):
t = threading.Thread(target=run)
lis.append(t)
t.start()
for t in lis:
t.join() #主線程等待子線程執(zhí)行完
print('over')
四,獲取多線程時執(zhí)行結(jié)果的返回值
例如我們做接口測試時候,需要獲取每個線程執(zhí)行時間
import threading
import time
import requests
run_times = []
#怎么獲取到多線程執(zhí)行的函數(shù)里面的返回值
def blog():
stat_time = time.time()
r = requests.get('http://www.nnzhp.cn/').text
end_time = time.time()
run_time = end_time-stat_time
run_times.append(run_time)
objs = []
for i in range(100):
t = threading.Thread(target=blog())
t.start()
objs.append(t)
for obj in objs:
obj.join()#join中可以設(shè)置timeout時間,主線程等待時間超過timeout時間后就會繼續(xù)執(zhí)行,不再等待
avg = sum(run_times)/len(run_times)
print('平均響應(yīng)時間是',avg)
五,守護線程:就相當于你是一個國王(非守護線程),然后你有很多仆人(守護線程),這些仆人都是為你服務(wù)的,一但你死了,那么你的仆人都給你陪葬。
主線程死掉了(執(zhí)行完了),那么不管子線程運行完否,都一起結(jié)束
import time
import threading def test():
time.sleep(2)
print('hhhh')
for i in range(5):
t=threading.Thread(target=test)
t.setDaemon(True)#設(shè)置子線程為守護線程
t.start()
程序執(zhí)行結(jié)果不會打印 hhhh,因為主線程執(zhí)行完的時候,子線程還沒執(zhí)行完,所以,主線程死掉了,守護子線程跟著消亡了
六、鎖:線程鎖就是,很多線程一起在操作一個數(shù)據(jù)的時候,可能會有問題,就要把這個數(shù)據(jù)加個鎖,同一時間只能有一個線程操作這個數(shù)據(jù)。
import threading
from threading import Lock num = 0
lock = Lock() # 申請一把鎖 def run():
global num
lock.acquire() # 加鎖
num += 1
lock.release() # 解鎖 lis = []
for i in range(5):
t = threading.Thread(target=run)
t.start()
lis.append(t)
for t in lis:
t.join()
print('over', num)
七,多進程:Python里面的多線程,是不能利用多核CPU的,如果想利用多核CPU的話,就得使用多進程,python中多進程使用multiprocessing模塊。
from multiprocessing import Process
import time def test(i):
time.sleep(1)
print(i) if __name__=='__main__':
for i in range(10):
p=Process(target=test,args=(i,))
p.start()
threading與實例對象提供了幾個方法可以讓我們更直觀的學(xué)習(xí)線程。
threading.active_count() # 返回當前運行的線程個數(shù)
threading.enumerate() # 返回當前運行中的線程list
threading.current_thread() # 返回當前的線程變量
t1.start() # 啟動線程
t1.is_alive() # 判斷線程是否在運行 運行指啟動后、終止前。
t1.getName() # 獲取線程名
t1.setName('填寫更改后的名稱') # 對線程進行命名
t1.setDaemon(True) # 設(shè)置守護線程
t1.isDaemon() # 判斷是否是守護線程
t1.join(timeout=20) # 阻塞當前上下文環(huán)境的線程,直到調(diào)用此方法的線程終止或到達指定的timeout(可選參數(shù))
總結(jié)
以上是生活随笔為你收集整理的Python基础-多线程与多进程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 茶七饭八酒满杯。求上联!
- 下一篇: Elasticsearch6.4.3文档