Python多任務之進程,內容包括 Process多進程,使用進程池完成多任務;其中 Process多進程 包括 進程的概念,使用Process完成多任務,進程和線程對比,通過隊列完成進程間通信,進程的狀態,獲取進程id;使用進程池完成多任務 包括 進程池的概念和語法,進程池拷貝文件夾等內容 ...
Process多進程
進程的概念
程式是沒有運行的代碼,靜態的;
進程是運行起來的程式,進程是一個程式運行起來之後和資源的總稱;
程式只有一個,但同一份程式可以有多個進程;例如,電腦上多開QQ;
程式和進程的區別在於有沒有資源,進程有資源而程式沒有資源,進程是一個資源分配的基本單元;
程式在沒運行的時候沒有資源,沒有顯卡,沒有網卡,等等;雙擊運行後有攝像頭,有網速等等,就叫做進程;
進程的狀態
進程狀態圖
- 就緒態:運行的條件都已經慢去,正在等在cpu執行
- 執行態:cpu正在執行其功能
- 等待態:等待某些條件滿足,例如一個程式sleep了,此時就處於等待態
使用Process完成多任務
進程的使用步驟和線程的使用步驟基本一致;
進程的使用步驟:
- 導入multiprocessing;
- 編寫多任務所所需要的函數;
- 創建multiprocessing.Process類的實例對象並傳入函數引用;
- 調用實例對象的start方法,創建子線程。
進程使用步驟圖示:
進程使用步驟代碼

import time import multiprocessing def sing(): while True: print("-----sing-----") time.sleep(1) def dance(): while True: print("-----dance-----") time.sleep(1) def main(): p1 = multiprocessing.Process(target=sing) p2 = multiprocessing.Process(target=dance) p1.start() p2.start() if __name__ == "__main__": main()使用Process完成多任務.py
運行結果:
-----sing-----
-----dance-----
-----sing-----
-----dance-----
-----sing-----
-----dance-----
......
進程:
- 主進程有什麼,子進程就會有什麼資源;
- 線程能創建多任務,進程也能創建多任務,但進程耗費的資源比較大;
- 所以運行的進程數,不一定越多越好;
- 當創建子進程時,會複製一份主進程的資源,代碼,記憶體等,但又會有自己不同的地方,比如pid等;
- 我們可以理解為多進程之間共用代碼,即只有一份代碼,但有多個指向同一代碼的箭頭;
- 能共用的就共用,不能共用的就拷貝一份;不需要修改的就共用,要修改的時候就給你拷貝一份,這就是寫時拷貝;
獲取進程id
獲取進程id代碼
from multiprocessing import Process import osdef run_proc(): """子進程要執行的代碼""" print('子進程運行中,pid=%d...' % os.getpid()) # os.getpid獲取當前進程的進程號 print('子進程將要結束...') if __name__ == '__main__': print('父進程pid: %d' % os.getpid()) # os.getpid獲取當前進程的進程號 p = Process(target=run_proc) p.start()
進程和線程對比
進程和線程的區別
- 進程是系統進行資源分配和調度的一個獨立單位;
- 線程是進程的一個實體,是CPU調度和分派的基本單位,即是操作系統調度的單位,它是比進程更小的能獨立運行的基本單位;
- 一個程式至少有一個進程,一個進程至少有一個線程;
- 線程的劃分尺度小於進程(資源比進程少),使得多線程程式的併發性高;
- 進程在執行過程中擁有獨立的記憶體單元,而多個線程共用記憶體,從而極大地提高了程式的運行效率;
- 線程不能夠獨立執行,必須依存在進程中;
- 進程先有,才有的線程;
- 線程用資源去做事;
- 多線程能實現多任務是指在一個進程資源裡面有多個箭頭;多線程是在同一個資源裡面有多個箭頭執行同一份代碼;
- 多進程的多任務是又開啟了一份資源,在這個資源裡面又有一個箭頭;
- 進程執行方式1:在一份資源裡面有多個箭頭在執行;
- 進程執行方式2:有多份資源,在每一份資源裡面有一個箭頭執行代碼;
- 線程執行開銷小,但不利於資源的管理和保護,進程正好相反;
- 開發中還是多線程用的多;
通過隊列完成進程間通信
隊列使用語法
# 創建隊列: from multiprocessing import Queue q = Queue(3) # 往隊列中添加數據: q.put(xxx) # 從隊列中獲取數據: q.get()
通過隊列完成進程間通信代碼

from multiprocessing import Queue import multiprocessing def download_data(q): """模擬這是從網上下載數據""" data = [11, 22, 33] for i in data: q.put(i) print("數據下載完成") def deal_data(q): """模擬處理從網上下載下來的數據""" data_list = [] while True: data = q.get() data_list.append(data) if q.empty(): break print("處理數據結束,數據為:", data_list) def main(): q = Queue(3) p1 = multiprocessing.Process(target=download_data, args=(q,)) p2 = multiprocessing.Process(target=deal_data, args=(q,)) p1.start() time.sleep(1) p2.start() if __name__ == '__main__': main()通過隊列完成進程間通信.py
運行結果:
數據下載完成
處理數據結束,數據為: [11, 22, 33]
進程池完成多任務
進程池
進程池的概念
因為進程的創建和銷毀是需要大量的資源的,為了減少消耗,當我們在處理多任務時,比如100個任務,我們可以先創建10個進程,然後用這10個進程來執行者100個任務,就可以重覆使用進程,達到節約資源的目的了,而這個就可以使用進程池。
進程池的創建
任務數固定且較少,用普通的進程即可;任務數不確定,且比較多,就用進程池;
進程池不會等待進程執行完畢,我們需要使用po.join()讓主進程等待進程池中的進程執行完;且po.close()必須在join前面;
創建進程池語法
# 創建進程池 from multiprocessing import Pool po = Pool(3) # 給進程池傳遞任務和參數 po.asyn(sing, (num,)) # 讓進程池等待子進程執行完 po.close() po.join()
進程池pool示例

from multiprocessing import Pool import os, time, random def worker(msg): t_start = time.time() print("%s開始執行,進程號為%d" % (msg, os.getpid())) # random.random()隨機生成0~1之間的浮點數 time.sleep(random.random() * 2) t_stop = time.time() print(msg, "執行完畢,耗時%0.2f" % (t_stop - t_start)) def main(): po = Pool(3) # 定義一個進程池,最大進程數3 for i in range(0, 10): # Pool().apply_async(要調用的目標,(傳遞給目標的參數元祖,)) # 每次迴圈將會用空閑出來的子進程去調用目標 po.apply_async(worker, (i,)) print("----start----") po.close() # 關閉進程池,關閉後po不再接收新的請求 po.join() # 等待po中所有子進程執行完成,必須放在close語句之後 print("-----end-----") if __name__ == '__main__': main()進程池pool示例.py
執行結果:

----start---- 0開始執行,進程號為7812 1開始執行,進程號為9984 2開始執行,進程號為1692 1 執行完畢,耗時0.65 3開始執行,進程號為9984 0 執行完畢,耗時1.08 4開始執行,進程號為7812 2 執行完畢,耗時1.82 5開始執行,進程號為1692 4 執行完畢,耗時1.12 6開始執行,進程號為7812 3 執行完畢,耗時1.35 7開始執行,進程號為9984 7 執行完畢,耗時0.11 8開始執行,進程號為9984 6 執行完畢,耗時0.50 9開始執行,進程號為7812 5 執行完畢,耗時0.65 8 執行完畢,耗時0.70 9 執行完畢,耗時0.74 -----end-----執行結果
多進程拷貝文件夾
多任務文件夾copy
步驟思路:
- 1.獲取用戶要拷貝的文件夾的名字;
- 2.創建一個新的文件夾;
- 3.獲取文件夾的所有待拷貝的文件名;listdir()
- 4.創建進程池;
- 5.複製原文件夾中的文件,到新文件夾的文件中去;
多任務拷貝文件代碼

import os from multiprocessing import Pool def copy_file(file, old_folder, new_folder): old_f = open(old_folder+"/"+file, "rb") data = old_f.read() old_f.close() new_f = open(new_folder+"/"+file, "wb") new_f.write(data) new_f.close() print("創建文件成功:", file) def main(): # 1.獲取要拷貝的文件夾 old_folder = input("請輸入你要拷貝的文件夾:") # 2.創建新文件夾 new_folder = old_folder + "_復件" try: os.mkdir(new_folder) print("創建文件夾成功") except Exception as e: pass # 3.獲取文件夾中所有待拷貝的文件,listdir() files_list = os.listdir(old_folder) # print(files_list) # 4.創建進程池 po = Pool(5) for file in files_list: # 向進程池中添加複製文件的任務 po.apply_async(copy_file, args=(file, old_folder, new_folder)) # 複製原文件夾中的文件,到新文件夾中 po.close() po.join() if __name__ == '__main__': main()使用進程池拷貝文件夾
在完成文件夾拷貝後,增加了一個需求,顯示拷貝文件的進度條,怎麼辦?
多任務拷貝文件並顯示進度條
如果要在進程池中使用Queue,要使用from multiprocessing import Manager ,使用Manager().Queue();
顯示進度條思路:
- 創建一個隊列;
- 往拷貝文件的函數中傳入隊列,拷貝好一個文件就往q中傳入該文件名;
- 在主函數中計算listdir()中的所有文件數量;
- 在主函數中定義一個num,初始值為0;
- 在主函數中定義一個while true,從q中獲取文件每獲取一個文件們就將num+1
- 計算,如果num的值大於等於總文件數量,就break;
- 使用已拷貝文件數量num除以總文件數量,即為拷貝的進度,使用開頭\r 和end=""讓顯示進度不換行,如下:
print("\r已拷貝文件%.2f %%" % (copy_ok_file_num*100/all_file_len), end="")
多任務拷貝文件並顯示進度條代碼

import os from multiprocessing import Pool, Manager def copy_file(q, file, old_folder, new_folder): old_f = open(old_folder+"/"+file, "rb") data = old_f.read() old_f.close() new_f = open(new_folder+"/"+file, "wb") new_f.write(data) new_f.close() q.put(file) def main(): # 1.獲取要拷貝的文件夾 old_folder = input("請輸入你要拷貝的文件夾:") # 2.創建新文件夾 new_folder = old_folder + "_復件" try: os.mkdir(new_folder) print("創建文件夾成功") except Exception as e: pass # 3.獲取文件夾中所有待拷貝的文件,listdir() files_list = os.listdir(old_folder) # 4.創建進程池 po = Pool(5) # 5.創建隊列 q = Manager().Queue() # 6.複製原文件夾中的文件,到新文件夾中 for file in files_list: # 向進程池中添加複製文件的任務 po.apply_async(copy_file, args=(q, file, old_folder, new_folder)) all_file_len = len(files_list) po.close() # po.join() copy_ok_file_num = 0 while True: file = q.get() copy_ok_file_num += 1 print("已拷貝文件%.2f %%" % (copy_ok_file_num*100/all_file_len)) # print("\r已拷貝文件%.2f %%" % (copy_ok_file_num*100/all_file_len), end="") if copy_ok_file_num >= all_file_len: break print() if __name__ == '__main__': main()多任務拷貝文件並顯示進度條.py