Python?多處理模塊如何使用示例詳解
什么是多處理模塊?
在本文中,我們將學習如何使用多處理模塊中的特定 Python 類(進程類)。我將通過示例為您提供快速概述。
還有什么比從官方文檔中提取模塊更好的方式來描述模塊呢? Multiprocessing
是一個使用類似于線程模塊的 API 支持生成進程的包。多處理包提供本地和遠程并發(fā),通過使用子進程而不是線程有效地回避全局解釋器鎖。
線程模塊不是本文的重點,但總而言之,線程模塊將處理一小段代碼執(zhí)行(輕量級且具有共享內(nèi)存),而多處理模塊將處理程序執(zhí)行(較重且完全隔離) 。
一般來說,多處理模塊提供了各種其他類、函數(shù)和實用程序,可用于處理程序執(zhí)行期間執(zhí)行的多個進程。如果程序需要在其工作流程中應(yīng)用并行性,該模塊專門設(shè)計為交互的主要點。我們不會討論多處理模塊中的所有類和實用程序,而是將重點關(guān)注一個非常具體的類,即進程類。
什么是進程類?
在本節(jié)中,我們將嘗試更好地介紹進程是什么,以及如何在 Python 中識別、使用和管理進程。正如 GNU C
庫中所解釋的:“進程是分配系統(tǒng)資源的基本單位。每個進程都有自己的地址空間和(通常)一個控制線程。一個進程執(zhí)行一個程序;可以讓多個進程執(zhí)行相同的程序程序,但每個進程在其自己的地址空間內(nèi)都有自己的程序副本,并獨立于其他副本執(zhí)行它。”
但這在 Python 中是什么樣子的呢?到目前為止,我們已經(jīng)設(shè)法對進程是什么、進程和線程之間的區(qū)別進行了一些描述和參考,但到目前為止我們還沒有觸及任何代碼。好吧,讓我們改變一下,用 Python 做一個非常簡單的流程示例:
#!/usr/bin/env python import os # A very, very simple process. if __name__ == "__main__": print(f"Hi! I'm process {os.getpid()}")
這將產(chǎn)生以下輸出:
[r0x0d@fedora ~]$ python /tmp/tmp.iuW2VAurGG/scratch.py
Hi! I'm process 144112
正如您所看到的,任何正在運行的 Python 腳本或程序都是它自己的一個進程。
創(chuàng)建子進程
那么在父進程中生成不同的子進程又如何呢?好吧,要做到這一點,我們需要多處理模塊中的 Process 類的幫助,它看起來像這樣:
#!/usr/bin/env python import os import multiprocessing def child_process(): print(f"Hi! I'm a child process {os.getpid()}") if __name__ == "__main__": print(f"Hi! I'm process {os.getpid()}") # Here we create a new instance of the Process class and assign our # `child_process` function to be executed. process = multiprocessing.Process(target=child_process) # We then start the process process.start() # And finally, we join the process. This will make our script to hang and # wait until the child process is done. process.join()
這將產(chǎn)生以下輸出:
[r0x0d@fedora ~]$ python /tmp/tmp.iuW2VAurGG/scratch.py
Hi! I'm process 144078
Hi! I'm a child process 144079
關(guān)于上一個腳本的一個非常重要的注意事項:如果您不使用 process.join() 來等待子進程執(zhí)行并完成,那么該點的任何其他后續(xù)代碼將實際執(zhí)行,并且可能會變得有點難以同步您的工作流程。
考慮以下示例:
#!/usr/bin/env python import os import multiprocessing def child_process(): print(f"Hi! I'm a child process {os.getpid()}") if __name__ == "__main__": print(f"Hi! I'm process {os.getpid()}") # Here we create a new instance of the Process class and assign our # `child_process` function to be executed. process = multiprocessing.Process(target=child_process) # We then start the process process.start() # And finally, we join the process. This will make our script to hang and # wait until the child process is done. #process.join() print("AFTER CHILD EXECUTION! RIGHT?!")
該代碼片段將產(chǎn)生以下輸出:
[r0x0d@fedora ~]$ python /tmp/tmp.iuW2VAurGG/scratch.py
Hi! I'm process 145489
AFTER CHILD EXECUTION! RIGHT?!
Hi! I'm a child process 145490
當然,斷言上面的代碼片段是錯誤的也是不正確的。這完全取決于您想要如何使用該模塊以及您的子進程將如何執(zhí)行。所以要明智地使用它。
創(chuàng)建各種子進程
如果要生成多個進程,可以利用 for 循環(huán)(或任何其他類型的循環(huán))。它們將允許您創(chuàng)建對所需流程的盡可能多的引用,并在稍后階段啟動/加入它們。
#!/usr/bin/env python import os import multiprocessing def child_process(id): print(f"Hi! I'm a child process {os.getpid()} with id#{id}") if __name__ == "__main__": print(f"Hi! I'm process {os.getpid()}") list_of_processes = [] # Loop through the number 0 to 10 and create processes for each one of # them. for i in range(0, 10): # Here we create a new instance of the Process class and assign our # `child_process` function to be executed. Note the difference now that # we are using the `args` parameter now, this means that we can pass # down parameters to the function being executed as a child process. process = multiprocessing.Process(target=child_process, args=(i,)) list_of_processes.append(process) for process in list_of_processes: # We then start the process process.start() # And finally, we join the process. This will make our script to hang # and wait until the child process is done. process.join()
這將產(chǎn)生以下輸出:
[r0x0d@fedora ~]$ python /tmp/tmp.iuW2VAurGG/scratch.py
Hi! I'm process 146056
Hi! I'm a child process 146057 with id#0
Hi! I'm a child process 146058 with id#1
Hi! I'm a child process 146059 with id#2
Hi! I'm a child process 146060 with id#3
Hi! I'm a child process 146061 with id#4
Hi! I'm a child process 146062 with id#5
Hi! I'm a child process 146063 with id#6
Hi! I'm a child process 146064 with id#7
Hi! I'm a child process 146065 with id#8
Hi! I'm a child process 146066 with id#9
數(shù)據(jù)通信
在上一節(jié)中,我描述了向 multiprocessing.Process
類構(gòu)造函數(shù)添加一個新參數(shù) args
。此參數(shù)允許您將值傳遞給子進程以在函數(shù)內(nèi)部使用。但你知道如何從子進程返回數(shù)據(jù)嗎?
您可能會認為,要從子級返回數(shù)據(jù),必須使用其中的 return 語句才能真正檢索數(shù)據(jù)。進程非常適合以隔離的方式執(zhí)行函數(shù),而不會干擾共享資源,這意味著我們知道從函數(shù)返回數(shù)據(jù)的正常且常用的方式。在這里,由于其隔離而不允許。
相反,我們可以使用隊列類,它將為我們提供一個在父進程與其子進程之間通信數(shù)據(jù)的接口。在這種情況下,隊列是一個普通的 FIFO(先進先出),具有用于處理多處理的內(nèi)置機制。
考慮以下示例:
#!/usr/bin/env python import os import multiprocessing def child_process(queue, number1, number2): print(f"Hi! I'm a child process {os.getpid()}. I do calculations.") sum = number1 + number2 # Putting data into the queue queue.put(sum) if __name__ == "__main__": print(f"Hi! I'm process {os.getpid()}") # Defining a new Queue() queue = multiprocessing.Queue() # Here we create a new instance of the Process class and assign our # `child_process` function to be executed. Note the difference now that # we are using the `args` parameter now, this means that we can pass # down parameters to the function being executed as a child process. process = multiprocessing.Process(target=child_process, args=(queue,1, 2)) # We then start the process process.start() # And finally, we join the process. This will make our script to hang and # wait until the child process is done. process.join() # Accessing the result from the queue. print(f"Got the result from child process as {queue.get()}")
它將給出以下輸出:
[r0x0d@fedora ~]$ python /tmp/tmp.iuW2VAurGG/scratch.py
Hi! I'm process 149002
Hi! I'm a child process 149003. I do calculations.
Got the result from child process as 3
異常處理
處理異常是一項特殊且有些困難的任務(wù),我們在使用流程模塊時必須不時地完成它。原因是,默認情況下,子進程內(nèi)發(fā)生的任何異常將始終由生成它的 Process
類處理。
下面的代碼引發(fā)帶有文本的異常:
#!/usr/bin/env python import os import multiprocessing def child_process(): print(f"Hi! I'm a child process {os.getpid()}.") raise Exception("Oh no! :(") if __name__ == "__main__": print(f"Hi! I'm process {os.getpid()}") # Here we create a new instance of the Process class and assign our # `child_process` function to be executed. Note the difference now that # we are using the `args` parameter now, this means that we can pass # down parameters to the function being executed as a child process. process = multiprocessing.Process(target=child_process) try: # We then start the process process.start() # And finally, we join the process. This will make our script to hang and # wait until the child process is done. process.join() print("AFTER CHILD EXECUTION! RIGHT?!") except Exception: print("Uhhh... It failed?")
輸出結(jié)果:
[r0x0d@fedora ~]$ python /tmp/tmp.iuW2VAurGG/scratch.py
Hi! I'm process 149505
Hi! I'm a child process 149506.
Process Process-1:
Traceback (most recent call last):
File "/usr/lib64/python3.11/multiprocessing/process.py", line 314, in _bootstrap
self.run()
File "/usr/lib64/python3.11/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "/tmp/tmp.iuW2VAurGG/scratch.py", line 7, in child_process
raise Exception("Oh no! :(")
Exception: Oh no! :(
AFTER CHILD EXECUTION! RIGHT?!
如果您跟蹤代碼,您將能夠注意到在 process.join()
調(diào)用之后仔細放置了一條 print
語句,以模擬父進程仍在運行,即使在子進程中引發(fā)了未處理的異常之后也是如此。
克服這種情況的一種方法是在子進程中實際處理異常,如下所示:
#!/usr/bin/env python import os import multiprocessing def child_process(): try: print(f"Hi! I'm a child process {os.getpid()}.") raise Exception("Oh no! :(") except Exception: print("Uh, I think it's fine now...") if __name__ == "__main__": print(f"Hi! I'm process {os.getpid()}") # Here we create a new instance of the Process class and assign our # `child_process` function to be executed. Note the difference now that # we are using the `args` parameter now, this means that we can pass # down parameters to the function being executed as a child process. process = multiprocessing.Process(target=child_process) # We then start the process process.start() # And finally, we join the process. This will make our script to hang and # wait until the child process is done. process.join() print("AFTER CHILD EXECUTION! RIGHT?!")
現(xiàn)在,您的異常將在您的子進程內(nèi)處理,這意味著您可以控制它會發(fā)生什么以及在這種情況下應(yīng)該做什么。
總結(jié)
當工作和實現(xiàn)依賴于并行方式執(zhí)行的解決方案時,多處理模塊非常強大,特別是與 Process
類一起使用時。這增加了在其自己的隔離進程中執(zhí)行任何函數(shù)的驚人可能性。
以上就是Python 多處理模塊如何使用示例詳解的詳細內(nèi)容,更多關(guān)于Python 多處理模塊的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python 多繼承中的一個詭異現(xiàn)象 既是 Father又是grandfather
我們知道,在面向?qū)ο缶幊汤锩?,繼承是一個很重要的概念。子類可以使用父類的方法和屬性,接下來小編將用舉例的方式為大家講解Python 多繼承中的一個詭異現(xiàn)象 其即是爸爸又是爺爺?shù)钠孑猬F(xiàn)象,感興趣的小伙伴可以看下面文章具體了解2021-09-09python使用django調(diào)用deepseek api搭建ai網(wǎng)站
DeepSeek是一家人工智能公司,致力于通過創(chuàng)新的技術(shù)和算法,推動人工智能領(lǐng)域的發(fā)展,本文給大家介紹了python使用django調(diào)用deepseek api搭建ai網(wǎng)站,文中有相關(guān)的代碼示例供大家參考,感興趣的小伙伴跟著小編一起來看看吧2025-02-02pycharm配置anaconda環(huán)境時找不到python.exe的兩種解決辦法
如果你在Anaconda中創(chuàng)建了虛擬環(huán)境,但是無法找到python.exe,可能是因為虛擬環(huán)境的Python路徑?jīng)]有添加到系統(tǒng)環(huán)境變量中,這篇文章主要給大家介紹了關(guān)于pycharm配置anaconda環(huán)境時找不到python.exe的兩種解決辦法,需要的朋友可以參考下2024-07-07PyCharm中鼠標懸停在函數(shù)上時顯示函數(shù)和幫助的解決方法
這篇文章主要介紹了PyCharm中鼠標懸停在函數(shù)上時顯示函數(shù)和幫助,本文給大家分享問題解決方法,對PyCharm鼠標懸停函數(shù)上顯示函數(shù)的解決方法感興趣的朋友跟隨小編一起看看吧2022-11-11