你能分清多进程与多线程吗?
總第127篇/張俊紅
今天我們來聊聊Python里面的多進程與多線程編程模式。
1.多線程工作
在開始講今天的正文之前,先給大家介紹一個概念「多線程工作」,這個概念可能有的人聽過,也可能有的人平常工作中就是這么做的。我再來給大家講講這個概念,所謂的「多線程工作」就是同時做好幾件事情。
拿我個人工作中例子來說,當我用Sql跑數的時候,數據不可能一下子就導出來,我會在一個屏幕上顯示Sql運行進度,在另一個屏幕上先做一會PPT,等Sql跑出來以后,我就又會迅速切換到處理剛剛導出來的數據。有的時候數據量很大,用Excel打開文件可能需要幾分鐘的時間,這個時候Excel是處于運行狀態,我是沒法在Excel上做別的事情,我會去微信上去處理別人的一些問題,當文件打開以后,我會迅速切換到Excel上繼續下一步處理,當我輸入一個公式以后,Excel可能又需要等待一會,這個時候我就可以再去做一些別的事情。
大家可以看到,我沒有在等一件事情徹底做完以后再去做另一件事情,而是在不同事情之間迅速切換,這種工作方式就可以算是一種「多線程工作」。
「多線程工作」可以減少你等待的時間,大大提高你的工作效率。
2.多進程與多線程
了解了「多線程工作」以后,我們開始進入今天的正題,編程里面的多線程和多進程。在上面的例子中Sql跑數可以算是一個進程、做PPT也可以算是一個進程、Excel處理數據還是一個進程。
進程下面還有一個更小的單位就是線程,一個進程由若干個線程組成,Sql跑數這個進程可以由寫Sql、運行Sql、導出數據這幾個線程組成。同樣,PPT制作這個進程可以由明確主題、選模板、列大綱、豐富頁面這幾個線程組成。
線程是程序執行的最小單位,一個進程可以由一個或多個線程組成,各個線程之間也是交叉執行。
這里需要注意的是,多進程/多線程并不能做到同時去做好幾件事情,而是把不同的事情交叉著做,做一段時間任務a,然后強制停止,去做一會任務b,再停止,再去做任務c。之所以會覺得各個任務之間是同時進行的原因是是任務與任務之間切換速度足夠快,這樣看起來就像是多個任務同時在進行。
我們再來看兩個概念:
并行:指在同一時刻,有多條指令在多個處理器上同時執行;
并發:指在同一時刻,只能有一條指令執行,但多個進程指令被快速輪換執行,使得在宏觀上具有多個進程同時執行的效果。
多份工作有多個人同時在做時就是并行,當多份工作由一個人交替在做時就是并發。在計算機中也是同樣的概念,計算機中CPU的核數就相當于人數,當計算機是單核多任務時就是并發;當計算機是多核且大于任務數時,就是并行。目前電腦主流配置都是四核/八線程的,而實際工作的任務數大都大于四個,所以也是需要交替來執行具體任務的,也就是并發執行。
上面就是關于多線程與多進程的一個簡單通俗的理解,一些太官方的解釋我就不在這里放了,大家感興趣的可以去自行上網查。
3.多進程與多線程是如何提高效率的
假設做任務A需要1個小時、任務B需要1個小時、任務C需要一個小時,當我們每個任務做20分鐘以后切換到另一個任務,這樣做完三個任務需要的總時間是不會變的,不僅不會變,反而可能會增加,因為在不同任務之間切換是需要代價的,因為當你從一個任務切換到另一個任務時很有可能不記得剛剛做到哪里了,還需要花時間想一想。那既然是這樣,我們為什么還要用多進程/多線程這種處理任務的方式呢?
我在第一小節里面提過,「多線程工作」可以減少你等待的時間,大大提高你的工作效率。是因為在實際工作中,有很多需要等待的地方,比如等待Excel打開,等待Sql跑出數據。多進程/多線程任務處理方式就是充分利用這些等待時間。讓你的大腦,計算機的大腦(CPU)得到充分的利用。如果要是沒有等待的時間,多進程/多線程的任務處理方式可能就不如單線程的了。
4.多進程與多線程是如何實現的
了解清楚了多進程與多線程是什么,以及是如何提高處理任務的效率的以后,我們進入到硬干貨部分,那就是具體多進程/多線程如何實現“同時”處理多任務的。
實現多任務的方式主要有以下幾種:
1、多進程模式
2、多線程模式
3、多進程+多線程
同時執行多個任務通常各個任務之間并不是沒有關聯的,而是需要相互通信和協調,有時,任務1必須暫停等待任務2完成后才能繼續執行,有時,任務3和任務4又不能同時執行,所以,多進程和多線程的程序的復雜度要遠遠高于我們前面寫的單進程單線程的程序。
4.1多進程模式
多進程就是一次啟動多個進程,每個進程只有一個線程,但多個進程可以一起執行多個任務。一般進程數默認是電腦CPU核數,當你的電腦是四核的時候,你的電腦進程默認就是4個。
4.1.1參數詳解
在Python中我們借助多進程包multiprocessing來進行多進程任務處理方式, multiprocessing模塊提供了一個Process類來代表一個進程對象,
#Process參數 multiprocessing.Process(group=None,?target=None,?name=None,?args=(),?kwargs={},?*,?daemon=None)#group分組 #target表示調用對象,即函數 #name表示進程的別名 #args表示調用對象的位置參數元組,即函數的參數 #kwargs表示調用對象的字典 #Process常用方法 close()?關閉進程 is_alive()?進程是否在運行 join()?等待join語句之前的所有程序執行完畢以后再繼續往下運行,通常用于進程間的同步 start()??進程準備就緒,等待CPU調度 run()??strat()調用run方法,如果實例化進程時沒有傳入target參數,這star執行默認run()方法 #Process常用屬性 pid?進程ID name?進程名字4.1.2建立一個子進程
下面的例子演示了啟動一個子進程(即單進程)并等待其結束:
from?multiprocessing?import?Process import?os#?子進程要執行的代碼def?run_proc(name):print('Run?child?process?%s?(%s)...'?%?(name,?os.getpid()))if?__name__=='__main__':print('Parent?process?%s.'?%?os.getpid())#用來獲取主進程的進程IDp?=?Process(target=run_proc,?args=('test',))#實例化進程p,調用run_proc函數,傳入參數對象argsprint('Child?process?will?start.')p.start()#進程準備就緒p.join()#待所有進程執行完畢以后執行后續操作print('Child?process?end.')運行結果如下:
Process?(876)?start... I?(876)?just?created?a?child?process?(877). I?am?child?process?(877)?and?my?parent?is?876.一個子進程其實就和我們平常調用單一函數是一樣的。
4.1.3建立多個子進程
建立多個子進程(即多進程),其實就是多個函數隨機同步運行。
建立多進程有兩種方法,一種是直接利用Process來建立多個子進程即可,如下:
from?multiprocessing?import?Process import?random,timedef?do_task(task):print('我正在做{}'.format(task))time.sleep(random.randint(1,3))def?write_task(task):print('我正在寫{}'.format(task))time.sleep(random.randint(1,3))if?__name__?==?"__main__":p1?=?Process(target=do_task,args=('PPT',))p2?=?Process(target=write_task,args=('Sql',))p1.start()p2.start()輸出結果為:
我正在做PPT 我正在寫Sql上面代碼表示同時啟動兩個進程,且兩個進程分別調用不同的函數,即做不同的任務。而且上面的任務數只有兩個,當任務數(需要調用的函數)較多時,我們如果還用上述的方法創建多進程,就需要實例化多個進程對象,并且寫多行p.start()比較麻煩,聰明的前輩們肯定不會用這么笨的方法,所以就有了進程池(Pool)。
multiprocessing.Pool?=?Pool(processes=None)#process為進程數把上面的二進程用進程池表示以后的結果如下:
import?multiprocessing import?random,timedef?do_task(task):print('我正在做{}'.format(task))time.sleep(random.randint(1,3))def?write_task(task):print('我正在寫{}'.format(task))time.sleep(random.randint(1,3))if?__name__?==?"__main__":func_list=[do_task,write_task]args_list=["PPT","Sql"]pool=multiprocessing.Pool(2)for?func,args?in?function_list,args_list:pool.apply_async(func,arg)???print?'Waiting?for?all?subprocesses?done...'pool.close()pool.join()????#調用join之前,一定要先調用close()?函數,否則會出錯print?'All?subprocesses?done.'輸出結果如下:
Waiting?for?all?subprocesses?done... 我正在做PPT 我正在寫Sql All?subprocesses?done.4.2多線程模式
多線程模式就是一次只啟動一個進程,但是在這個進程里面可以啟動多個線程,這樣多個線程就可以一起執行多個任務,在Python中我們要啟動多線程借助于threading模塊,用于 啟動多線程的模塊還有_thread模塊,但是threading模塊是封裝了_thread模塊,且比較高級,所以我們一般使用threading模塊即可。
4.2.1參數詳解
啟動多線程使用的是threading模塊中的Thread類,構建時使用的參數和方法與Process基本一致,大家看看即可,這里就不贅述了。
#參數 Thread(group=None,?target=None,?name=None,?args=(),?kwargs={})? #方法 isAlive() get/setName(name)?獲取/設置線程名 start()? join()?4.2.2創建一個線程
創建一個線程就是調用一個函數。
import?time,?threadingdef?do_chioce(task):print('我正在{}'.format(task))time.sleep(random.randint(1,3))if?__name__?==?"__main__":t?=?threading.Thread(target=do_chioce,args=('選PPT模板',))t.start()輸出結果為:
我正在選PPT模板4.2.3創建多個線程
創建多個線程就是調用多個函數。
import?time,?threadingdef?do_chioce(task):print('我正在{}'.format(task))time.sleep(random.randint(1,3))def?do_content(task):print('我正在{}'.format(task))time.sleep(random.randint(1,3))if?__name__?==?"__main__":t1?=?threading.Thread(target=do_chioce,args=('選PPT模板',))t2?=?threading.Thread(target=do_content,args=('列PPT大綱',))t1.start()t2.start()輸出結果為:
我正在選PPT模板 我正在列PPT大綱4.3多進程+多線程
多進程+多線程就是一次啟動多個進程,每個進程又啟動多個線程,這樣同時執行的任務就會很多,但是模型相對復雜,不建議使用。
你還可以看:
推薦一款程序員專用的編輯器
推薦一波優質資源
總結
以上是生活随笔為你收集整理的你能分清多进程与多线程吗?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 影像质感双越级realme新机真我11系
- 下一篇: 动视巨变:PC 收入首次超过主机,暴雪游