網站首頁 編程語言 正文
該章節我們來學習一下在 Python 中去創建并使用多進程的方法,通過學習該章節,我們將可以通過創建多個進程來幫助我們提高腳本執行的效率。可以認為縮短腳本執行的時間,就是提高執行我們腳本的效率。接下來讓我們都看一下今天的章節知識點都有哪些?
進程的創建模塊 - multiprocessing
創建進程函數 - Process
函數名 | 介紹 | 參數 | 返回值 |
---|---|---|---|
Process | 創建一個進程 | target, args | 進程對象 |
Process功能介紹:實例化一個對象;它需要傳入兩個參數 target 與 args:target 是一個函數,args 是對應一個函數的參數(args參數是一個元組)。其實我們可以這樣去理解,在一個腳本中創建子進程,目的是為了讓它執行我們腳本中的某個函數。換句話講,我們將腳本中的某一個函數單獨的啟用一個進程去執行。
我們說過進程之間互不干擾,可以同時執行。所以我們可以認為主進程中的程序和子進程的函數是相互不干擾的,聽起來可能很難理解,一會兒下文我們進行一個案例的小練習,一遍幫助大家去更好的理解其中的含義。
進程的常用方法
函數名 | 介紹 | 參數 | 返回值 |
---|---|---|---|
start | 執行進程 | 無 | 無 |
join | 阻塞進程 | 無 | 無 |
kill | 殺死進程 | 無 | 無 |
is_alive | 判斷進程是否存活 | 無 | bool |
- start 函數:通過調用它,可以直接啟動我們創建的進程。它會馬上執行我們進程中傳入的函數,start 函數沒有任何參數,也沒有返回值。
- join 函數:我們說過,主進程和子進程的程序會同時運行,互不影響。這樣就會有一個問題,有可能是 子進程 先執行完它的業務,也有可能是 主進程 先執行完它的業務邏輯。如果有的時候我們必須要先執行完 子進程的業務 再執行 主進程的業務 。則通過調用 join 函數,在這一函數下面執行的主進程業務要等待子進程完成之后才會繼續執行。我們將 join 這樣的函數叫做 等待/阻塞函數。join 函數沒有任何參數,也沒有返回值。
- kill 函數:如果我們在執行子進程的過程中發現不需要這個子進程繼續運行了,就可以使用 kill 函數殺死當前的這個子進程,殺死的這個子進程不會在執行子進程中函數的業務邏輯。kill 函數沒有任何參數,也沒有返回值。
- is_alive 函數:通過調用這個函數可以判斷當前的進程是否是存活狀態,它返回一個 bool 值。True 表示當前進程還在,程序還在繼續執行;如果是 False 則代表當前進程已經結束了
start 函數
演示案例:
- 我們先定義兩個簡單的函數,每個函數定義兩個簡單的 for 循環。
- 每執行一次循環,休眠一秒的時間。
- 在兩次循環的開始定義一個實例化時間對象,用以計算兩次循環的時間間隔。
- 同時,獲取腳本執行的進程號; 看看是一個怎樣的結果。
# coding:utf-8 import time import os def work_for_first(): for i in range(5): print('\'work_for_first\' 函數的循環值:%s', '進程號為:%s' % i, os.getpid()) # os.getpid() 為獲取進程號函數 time.sleep(1) def work_for_second(): for i in range(5): print('\'work_for_second\' 函數的循環值:%s', '進程號為:%s' % i, os.getpid()) time.sleep(1) if __name__ == '__main__': start_time = time.time() # 獲取執行 循環 之前的時間戳 work_for_first() work_for_second() end_time = time.time() - start_time # 獲取執行 循環 結束的時間戳 print('耗時時間為:{}, 進程號為:{}'.format(end_time, os.getpid())) # 獲取耗時與進程號
執行結果如下圖:
OKK!接下來進入我們今天要學習的主題。
將 work_for_first() 函數創建一個新的子進程去執行。
# coding:utf-8 import time import os import multiprocessing def work_for_first(): for i in range(5): print('\'work_for_first\' 函數的循環值:{},進程號為:{}'.format(i, os.getpid())) time.sleep(1) def work_for_second(): for i in range(5): print('\'work_for_second\' 函數的循環值:{},進程號為:{}'.format(i, os.getpid())) time.sleep(1) if __name__ == '__main__': start_time = time.time() # 獲取執行 循環 之前的時間戳 work_for_first_process = multiprocessing.Process(target=work_for_first) # 因為我們傳入的函數沒有參數所以 args 可以不寫 work_for_first_process.start() work_for_second() end_time = time.time() - start_time # 獲取執行 循環 結束的時間戳 print('耗時時間為:{}, 進程號為:{}'.format(end_time, os.getpid())) # 獲取耗時與進程號
執行結果如下圖:
因為我們針對 work_for_first() 函數創建一個新的子進程去執行,所以我們的耗時變為了 5秒。那么如果我們將 work_for_second() 函數也創建一個新的子進程去執行,耗時又會是多少呢?我們接著往下看。
# coding:utf-8 import time import os import multiprocessing def work_for_first(): for i in range(5): print('\'work_for_first\' 函數的循環值:{},進程號為:{}'.format(i, os.getpid())) time.sleep(1) def work_for_second(): for i in range(5): print('\'work_for_second\' 函數的循環值:{},進程號為:{}'.format(i, os.getpid())) time.sleep(1) if __name__ == '__main__': start_time = time.time() # 獲取執行 循環 之前的時間戳 work_for_first_process = multiprocessing.Process(target=work_for_first) # 因為我們傳入的函數沒有參數所以 args 可以不寫 work_for_first_process.start() work_for_second_process = multiprocessing.Process(target=work_for_second) work_for_second_process.start() end_time = time.time() - start_time # 獲取執行 循環 結束的時間戳 print('耗時時間為:{}, 進程號為:{}'.format(end_time, os.getpid())) # 獲取耗時與進程號
執行結果如下圖:
PS:從腳本中執行入口的 main 函數可以看出 work_for_first() 函數 與 work_for_second() 函數 分別都由各自的子進程來執行,主進程實際執行的 只有 23行、29行、30行代碼,所以從耗時來看,主進程實際上只執行了 0.026 秒。
這里再思考一個問題,如果是每一個子進程都單獨的通過 .start 去啟動,那么在子進程很多的情況下,啟動的確實會有一些慢了。這個時候我們就可以通過 for 循環的方式去啟動子進程。方式如下:
for sun_process in (work_for_first_process, work_for_second_process): sun_process.start()
join 函數
同樣的也會存在著這樣一種情況,我們希望子進程運行結束之后再去執行我們的主進程,這時候我們就會使用到 join 函數 。
這里我們就利用上文的 進程 for循環同時啟動兩個子進程,然后我們再在下一個 for循環 執行 join 函數,我們看看會發生什么。
# coding:utf-8 import time import os import multiprocessing def work_for_first(): for i in range(5): print('\'work_for_first\' 函數的循環值:{},進程號為:{}'.format(i, os.getpid())) time.sleep(1) def work_for_second(): for i in range(5): print('\'work_for_second\' 函數的循環值:{},進程號為:{}'.format(i, os.getpid())) time.sleep(1) if __name__ == '__main__': start_time = time.time() # 獲取執行 循環 之前的時間戳 work_for_first_process = multiprocessing.Process(target=work_for_first) # 因為我們傳入的函數沒有參數所以 args 可以不寫 # work_for_first_process.start() work_for_second_process = multiprocessing.Process(target=work_for_second) # work_for_second_process.start() for sun_process in (work_for_first_process, work_for_second_process): sun_process.start() for sun_process in (work_for_first_process, work_for_second_process): sun_process.join() end_time = time.time() - start_time # 獲取執行 循環 結束的時間戳 print('耗時時間為:{}, 進程號為:{}'.format(end_time, os.getpid())) # 獲取耗時與進程號
執行結果如下圖:
kill 函數 與 is_alive 函數
接下來我們再嘗試一個場景,利用 for 循環,我們同時啟動 work_for_first() 函數 與 work_for_second() 函數 的子進程。然后我們再在另一個 for 循環中,將 work_for_second() 函數 的子進程 kill 掉,然后判斷兩個子進程的存活狀態。
示例腳本如下:
# coding:utf-8 import time import os import multiprocessing def work_for_first(): for i in range(5): print('\'work_for_first\' 函數的循環值:{},進程號為:{}'.format(i, os.getpid())) time.sleep(1) def work_for_second(): for i in range(5): print('\'work_for_second\' 函數的循環值:{},進程號為:{}'.format(i, os.getpid())) time.sleep(1) if __name__ == '__main__': start_time = time.time() # 獲取執行 循環 之前的時間戳 work_for_first_process = multiprocessing.Process(target=work_for_first) # 因為我們傳入的函數沒有參數所以 args 可以不寫 # work_for_first_process.start() work_for_second_process = multiprocessing.Process(target=work_for_second) # work_for_second_process.start() for sun_process in (work_for_first_process, work_for_second_process): sun_process.start() time.sleep(1) # 休眠一秒是為了 work_for_second_process 子進程 至少能夠運行一次 for sun_process in (work_for_first_process, work_for_second_process): work_for_second_process.kill() if work_for_first_process.is_alive(): print('\'work_for_first_process\' 子進程當前存活狀態為:True') elif not work_for_second_process.is_alive(): print('\'work_for_second_process\' 子進程當前存活狀態為:False') sun_process.join() end_time = time.time() - start_time # 獲取執行 循環 結束的時間戳 print('耗時時間為:{}, 進程號為:{}'.format(end_time, os.getpid())) # 獲取耗時與進程號
運行結果如下:
進程的相關問題
通過學習多進程的創建、啟動,我們可以充分的體會到進程給我們帶來的好處。它可以使我們的腳本程序執行時間進行縮短,從而提高工作效率。
然而多進程也有一些問題:
- 通過進程模塊執行的函數無法獲取返回值,即便這個函數擁有 return 關鍵字也無法獲取到,這也是我們進程的弊端。
- 多個進程同時修改文件可能會出現錯誤。
- 進程數量太多可能會造成資源不足、甚至死機等情況。
關于進程的這些問題,其實也并不是不能解決。在后續更新的 進程間的通信 、進程池與進程鎖 的章節我們再進行詳細的介紹。
原文鏈接:https://blog.csdn.net/weixin_42250835/article/details/124030773
相關推薦
- 2023-07-13 react中useState的基本用法
- 2022-03-27 MongoDB4.28開啟權限認證配置用戶密碼登錄功能_MongoDB
- 2022-09-19 Tomcat配置HTTPS訪問的實現步驟_Tomcat
- 2022-09-04 Go語言簡介和環境配置_Golang
- 2022-11-18 如何使用Python生成Hilbert矩陣_python
- 2023-02-14 React?Hydrate原理源碼解析_React
- 2022-04-28 Python語言中的數據類型-序列_python
- 2022-01-21 Docker報錯:OCI runtime exec failed: exec failed: con
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支