python教程之進(jìn)程和線程
進(jìn)程和線程的區(qū)別和聯(lián)系
終于開始加深難度,來(lái)到進(jìn)程和線程的知識(shí)點(diǎn)~
單就這兩個(gè)概念,就難倒過(guò)不少初學(xué)者——今天學(xué)了概念,明天就忘記;明天學(xué)了例子,又忘記了概念。
要理解進(jìn)程和線程的聯(lián)系和區(qū)別,我舉個(gè)特簡(jiǎn)單的例子:
你的電腦有兩個(gè)瀏覽器,一個(gè)谷歌瀏覽器,一個(gè)qq瀏覽器。
一個(gè)瀏覽器就是一個(gè)進(jìn)程。
然后,你打開了谷歌瀏覽器,百度搜索了測(cè)試奇譚,又新開一個(gè)標(biāo)簽頁(yè),打開譚叔的文章,如下圖所示:
你可以這樣理解——在同一個(gè)瀏覽器打開的兩個(gè)網(wǎng)頁(yè)就是兩個(gè)線程
。如果我關(guān)閉了瀏覽器,這兩個(gè)線程也沒有了。
好了,當(dāng)你有了概念后,我才好講兩者的區(qū)別和聯(lián)系。
進(jìn)程
- 優(yōu)點(diǎn)
穩(wěn)定性高
,當(dāng)程序崩潰后,不影響其他進(jìn)程的使用。即谷歌瀏覽器崩潰后,qq瀏覽器還可以正常使用。
- 缺點(diǎn)
創(chuàng)建進(jìn)程的代價(jià)大
。即當(dāng)你開了各種各樣的瀏覽器后,你的電腦會(huì)特別卡,因?yàn)殡娔X內(nèi)存和CPU有上限。
線程
- 優(yōu)點(diǎn)
- 多線程通常比多進(jìn)程快一點(diǎn),但優(yōu)勢(shì)不大
- 缺點(diǎn)
- 任何一個(gè)線程掛掉會(huì)造成整個(gè)進(jìn)程崩潰,因?yàn)榫€程共享進(jìn)程的內(nèi)存(瀏覽器的例子不再適用,可以理解為綁在一條船上的螞蚱)
多進(jìn)程
因?yàn)榇蠖鄶?shù)小伙伴用的Windows操作系統(tǒng),所以針對(duì)Unix/Linux的fork()調(diào)用拋開不談。
在python,一般使用multiprocessing實(shí)現(xiàn)多進(jìn)程。
import os from multiprocessing import Process def run\_proc(name): print('開始執(zhí)行子進(jìn)程 %s (%s)…' % (name, os.getpid())) # 子進(jìn)程要執(zhí)行的代碼 if __name__ == '\_\_main\_\_': print('父進(jìn)程 %s.' % os.getpid()) p = Process(target=run_proc, args=('test',)) # 創(chuàng)建一個(gè)Process實(shí)例 print('子進(jìn)程即將開始.') p.start() # 用start()方法啟動(dòng)實(shí)例 p.join() # join()方法可以等待子進(jìn)程結(jié)束后再繼續(xù)往下運(yùn)行,通常用于進(jìn)程間的同步 print('子進(jìn)程結(jié)束.')
要細(xì)講嗎?
其實(shí),我的備注寫得很全,你只需copy代碼下來(lái)執(zhí)行一次,或者debug一次,就能明白。
線程池
如何理解?
即代碼可運(yùn)行的進(jìn)程數(shù)量,有個(gè)地方管控它。
from multiprocessing import Pool import os import time import random def long\_time\_task(name): print('開始 task %s (%s)...' % (name, os.getpid())) start = time.time() time.sleep(random.random() * 3) end = time.time() print('Task %s 執(zhí)行花費(fèi) %0.2f 秒.' % (name, (end - start))) if __name__ == '\_\_main\_\_': print('父親進(jìn)程 %s.' % os.getpid()) p = Pool(3) # 因?yàn)镻ool的默認(rèn)大小是4,故task 0,1,2,3是立刻執(zhí)行的,而task 4要等待前面某個(gè)task完成后才執(zhí)行,但最多同時(shí)執(zhí)行4個(gè)進(jìn)程 # 由于Pool的默認(rèn)大小是CPU的核數(shù),如果你擁有8核CPU,要提交至少9個(gè)子進(jìn)程才能看到等待效果 for i in range(5): p.apply_async(long_time_task, args=(i,)) print('等待子進(jìn)程結(jié)束...') p.close() # 對(duì)Pool對(duì)象調(diào)用join()方法會(huì)等待所有子進(jìn)程執(zhí)行完畢 # 調(diào)用join()之前必須先調(diào)用close(),調(diào)用close()之后就不能繼續(xù)添加新的Process了 p.join() print('所有子進(jìn)程已執(zhí)行.')
以上,是必知必會(huì)的。
當(dāng)然,最好的學(xué)習(xí)時(shí)機(jī)是:當(dāng)你要用時(shí),再來(lái)復(fù)盤學(xué),效果最佳。
如果你學(xué)了,沒有使用場(chǎng)景,我建議緩一緩學(xué)或者作為知識(shí)儲(chǔ)備。
多線程
多線程有三點(diǎn)必須提前明確:
- 多任務(wù)需求可以由多進(jìn)程完成,也可以由一個(gè)進(jìn)程內(nèi)的多線程完成
- 進(jìn)程是由若干線程組成
- 一個(gè)進(jìn)程至少有一個(gè)線程
Python的標(biāo)準(zhǔn)庫(kù)提供了兩個(gè)模塊:_thread和threading,_thread是低級(jí)模塊,我們一般使用高級(jí)模塊threading(對(duì)_thread進(jìn)行過(guò)封裝)。
啟動(dòng)一個(gè)線程就是把一個(gè)函數(shù)傳入并創(chuàng)建Thread實(shí)例,然后調(diào)用start()開始執(zhí)行,我們看一個(gè)簡(jiǎn)單的例子:
import time import threading # 新線程執(zhí)行的代碼 def loop(): # 由于任何進(jìn)程默認(rèn)就會(huì)啟動(dòng)一個(gè)線程,我們把該線程稱為主線程,主線程又可以啟動(dòng)新的線程, # Python的threading模塊有個(gè)current\_thread()函數(shù),它永遠(yuǎn)返回當(dāng)前線程的實(shí)例 print('線程ss %s 運(yùn)行中…' % threading.current_thread().name) n = 0 # 主線程實(shí)例的名字叫MainThread,子線程的名字在創(chuàng)建時(shí)指定,我們用LoopThread命名子線程,在打印輸出的時(shí)候顯示名字 while n < 5: n = n + 1 print('線程ss %s >>> %s' % (threading.current_thread().name, n)) time.sleep(1) print('線程ss %s 已結(jié)束.' % threading.current_thread().name) print('線程 %s is 運(yùn)行中…' % threading.current_thread().name) t = threading.Thread(target=loop, name='LoopThread') t.start() t.join() ''' 對(duì)于 join()方法而言,其另一個(gè)重要方面是其實(shí)它根本不需要調(diào)用。 一旦線程啟動(dòng),它們 就會(huì)一直執(zhí)行,直到給定的函數(shù)完成后退出。 如果主線程還有其他事情要去做,而不是等待這些線程完成(例如其他處理或者等待新的客戶端請(qǐng)求), 就可以不調(diào)用 join()。join()方法只有在你需要等待線程完成的時(shí)候才是有用的 ''' print('線程 %s 已結(jié)束.' % threading.current_thread().name)
同樣,以上內(nèi)容,是必知必會(huì)的。
并且,工作場(chǎng)景,我們一般會(huì)使用多線程處理問(wèn)題,而非多進(jìn)程。(注意:是一般)
至于進(jìn)程間通信、線程鎖、GIL鎖、多線程變量、線程間通信、異步協(xié)程等知識(shí),講起來(lái)比較復(fù)雜,也不是極簡(jiǎn)教程的核心,你可以先自學(xué),或者當(dāng)你真正要使用它的時(shí)候再去看,再去學(xué)。
總結(jié)
01 多線程、多進(jìn)程,是必知必會(huì)的;
02 學(xué)習(xí)進(jìn)度自己琢磨,既不能死磕,亦不能簡(jiǎn)單跳過(guò);
03 小伙伴比較關(guān)心,面試時(shí)會(huì)不會(huì)被問(wèn)到。答:一般公司不會(huì),so?
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Python爬蟲進(jìn)階之Beautiful Soup庫(kù)詳解
這篇文章主要介紹了Python爬蟲進(jìn)階之Beautiful Soup庫(kù)詳解,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)python爬蟲的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04在Python中使用AOP實(shí)現(xiàn)Redis緩存示例
本篇文章主要介紹了在Python中使用AOP實(shí)現(xiàn)Redis緩存示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07python?pip?install總是報(bào)錯(cuò)情況分析及解決辦法
這篇文章主要給大家介紹了關(guān)于python?pip?install總是報(bào)錯(cuò)情況分析及解決辦法,安裝包時(shí)經(jīng)常遇到報(bào)錯(cuò),這里提供兩種方式解決,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10利用python實(shí)現(xiàn)全屏愛心雨向喜歡的人表白
馬上520了,教大家用Python做一個(gè)下愛心雨的特效,這篇文章主要給大家介紹了關(guān)于利用python實(shí)現(xiàn)全屏愛心雨向喜歡的人表白的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05tensorflow 輸出權(quán)重到csv或txt的實(shí)例
今天小編就為大家分享一篇tensorflow 輸出權(quán)重到csv或txt的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-06-06Python內(nèi)置函數(shù) next的具體使用方法
這篇文章主要介紹了Python內(nèi)置函數(shù) next的具體使用方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11python使用aiohttp通過(guò)設(shè)置代理爬取基金數(shù)據(jù)簡(jiǎn)單示例
這篇文章主要為大家介紹了python使用aiohttp通過(guò)設(shè)置代理爬取基金數(shù)據(jù)簡(jiǎn)單示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06聊聊Python代碼中if?__name__?==?‘__main__‘的作用是什么
一個(gè)python文件通常有兩種使用方法,第一是作為腳本直接執(zhí)行,第二是 import 到其他的python腳本中被調(diào)用執(zhí)行,這篇文章主要給大家介紹了關(guān)于Python代碼中if?__name__?==?‘__main__‘的作用是什么的相關(guān)資料,需要的朋友可以參考下2022-03-03

Pytorch實(shí)現(xiàn)張量的創(chuàng)建與使用方法