在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ 多進(jìn)程
事件驅(qū)動(dòng)程序
反應(yīng)式編程
進(jìn)程池
線(xiàn)程
線(xiàn)程池
Python并發(fā)簡(jiǎn)介
并發(fā)vs并行
同步線(xiàn)程
調(diào)試線(xiàn)程應(yīng)用程序
進(jìn)程間通信
線(xiàn)程通信
Python并發(fā)編程教程
測(cè)試線(xiàn)程應(yīng)用程序
基準(zhǔn)和性能分析
系統(tǒng)和內(nèi)存架構(gòu)
線(xiàn)程的實(shí)現(xiàn)
多進(jìn)程

多進(jìn)程

在本章中,我們將更多地關(guān)注多處理和多線(xiàn)程之間的比較。

多進(jìn)程

在一臺(tái)計(jì)算機(jī)系統(tǒng)中使用兩個(gè)或多個(gè)CPU單元。 通過(guò)利用計(jì)算機(jī)系統(tǒng)中可用的全部CPU核心,這是最好的方法來(lái)充分利用我們的硬件。

多線(xiàn)程

這是CPU通過(guò)同時(shí)執(zhí)行多個(gè)線(xiàn)程來(lái)管理操作系統(tǒng)使用的能力。 多線(xiàn)程的主要思想是通過(guò)將進(jìn)程分成多個(gè)線(xiàn)程來(lái)實(shí)現(xiàn)并行性。

下表顯示了它們之間的一些重要區(qū)別 -

編號(hào) 多進(jìn)程 多程序
1 多處理是指多個(gè)CPU同時(shí)處理多個(gè)進(jìn)程。 多程序同時(shí)在主存儲(chǔ)器中保存多個(gè)程序,并使用單個(gè)CPU同時(shí)執(zhí)行它們。
2 它利用多個(gè)CPU。 它利用單個(gè)CPU
3 它允許并行處理。 上下文切換。
4 處理工作的時(shí)間更少。 處理工作需要花費(fèi)更多的時(shí)間。
5 它有助于計(jì)算機(jī)系統(tǒng)設(shè)備的高效利用。 效率低于多重處理。
6 系統(tǒng)通常更昂貴。 這樣的系統(tǒng)更便宜。

消除全局解釋器鎖定(GIL)的影響

在使用并發(fā)應(yīng)用程序時(shí),Python中存在一個(gè)名為GIL(全局解釋器鎖)的限制。 GIL從來(lái)不允許我們利用CPU的多個(gè)內(nèi)核,因此可以說(shuō)Python中沒(méi)有真正的線(xiàn)程。 GIL是互斥鎖 - 互斥鎖,它使線(xiàn)程安全。 換句話(huà)說(shuō),可以說(shuō)GIL阻止了多個(gè)線(xiàn)程并行執(zhí)行Python代碼。鎖一次只能由一個(gè)線(xiàn)程保存,如果想執(zhí)行一個(gè)線(xiàn)程,那么它必須先獲取鎖。

通過(guò)使用多處理,可以通過(guò)GIL有效地繞過(guò) -

  • 通過(guò)使用多處理,利用多個(gè)進(jìn)程的能力,因此使用GIL的多個(gè)實(shí)例。
  • 由于這個(gè)原因,在程序中一次執(zhí)行一個(gè)線(xiàn)程的字節(jié)碼沒(méi)有限制。

在Python中啟動(dòng)進(jìn)程

可以使用以下三種方法在多處理模塊內(nèi)用Python啟動(dòng)進(jìn)程 -

  • Fork
  • Spawn
  • Forkserver

使用Fork創(chuàng)建一個(gè)流程
Fork命令是在UNIX中找到的標(biāo)準(zhǔn)命令。 它用于創(chuàng)建稱(chēng)為子進(jìn)程的新進(jìn)程。 此子進(jìn)程與稱(chēng)為父進(jìn)程的進(jìn)程同時(shí)運(yùn)行。 這些子進(jìn)程也與其父進(jìn)程相同,并繼承父進(jìn)程可用的所有資源。 使用Fork創(chuàng)建流程時(shí)使用以下系統(tǒng)調(diào)用 -

  • fork() - 這是一個(gè)通常在內(nèi)核中實(shí)現(xiàn)的系統(tǒng)調(diào)用,它用于創(chuàng)建進(jìn)程的副本。
  • getpid() - 該系統(tǒng)調(diào)用返回調(diào)用進(jìn)程的進(jìn)程ID(PID)。

示例
以下Python腳本示例將演示如何創(chuàng)建新的子進(jìn)程并獲取子進(jìn)程和父進(jìn)程的PID -

import os

def child():
   n = os.fork()

   if n > 0:
      print("PID of Parent process is : ", os.getpid())

   else:
      print("PID of Child process is : ", os.getpid())
child()

執(zhí)行上面示例代碼,得到以下結(jié)果 -

PID of Parent process is : 25989
PID of Child process is : 25990

用Spawn創(chuàng)建一個(gè)進(jìn)程

Spawn意味著開(kāi)始新的事物。 因此,產(chǎn)生一個(gè)過(guò)程意味著父過(guò)程創(chuàng)建一個(gè)新進(jìn)程。 父進(jìn)程異步繼續(xù)執(zhí)行或等待子進(jìn)程結(jié)束其執(zhí)行。 按照這些步驟產(chǎn)生一個(gè)進(jìn)程 -

  • 導(dǎo)入多處理模塊。
  • 創(chuàng)建對(duì)象進(jìn)程。
  • 通過(guò)調(diào)用start()方法來(lái)啟動(dòng)進(jìn)程活動(dòng)。
  • 等待進(jìn)程完成其工作并通過(guò)調(diào)用join()方法退出。

示例

以下Python腳本示例產(chǎn)生三個(gè)進(jìn)程 -

import multiprocessing

def spawn_process(i):
   print ('This is process: %s' %i)
   return

if __name__ == '__main__':
   Process_jobs = []
   for i in range(3):
   p = multiprocessing.Process(target = spawn_process, args = (i,))
      Process_jobs.append(p)
   p.start()
   p.join()

執(zhí)行上面示例代碼,得到以下結(jié)果 -

This is process: 0
This is process: 1
This is process: 2

使用Forkserver創(chuàng)建一個(gè)進(jìn)程

Forkserver機(jī)制僅適用于那些支持通過(guò)Unix Pipes傳遞文件描述符的所選UNIX平臺(tái)。 考慮以下幾點(diǎn)來(lái)理解Forkserver機(jī)制的工作 -

  • 服務(wù)器通過(guò)使用Forkserver機(jī)制來(lái)啟動(dòng)新進(jìn)程。
  • 然后服務(wù)器接收命令并處理創(chuàng)建新進(jìn)程的所有請(qǐng)求。
  • 要?jiǎng)?chuàng)建一個(gè)新的進(jìn)程,python程序會(huì)向Forkserver發(fā)送一個(gè)請(qǐng)求,之后它會(huì)創(chuàng)建一個(gè)進(jìn)程。
  • 最后,我們可以在程序中使用這個(gè)新創(chuàng)建的進(jìn)程。

守護(hù)進(jìn)程如何在Python中進(jìn)行處理

Python多處理模塊允許通過(guò)它的守護(hù)進(jìn)程選項(xiàng)來(lái)守護(hù)進(jìn)程。 守護(hù)進(jìn)程或在后臺(tái)運(yùn)行的進(jìn)程遵循與守護(hù)進(jìn)程線(xiàn)程類(lèi)似的概念。 要在后臺(tái)執(zhí)行該進(jìn)程,需要將守護(hù)進(jìn)程標(biāo)志設(shè)置為true。 只要主進(jìn)程正在執(zhí)行,守護(hù)進(jìn)程將繼續(xù)運(yùn)行,并在完成執(zhí)行或主程序被終止后終止進(jìn)程。

示例

在這里,我們使用與守護(hù)進(jìn)程線(xiàn)程中使用的相同的示例。 唯一的區(qū)別是模塊從多線(xiàn)程更改為多處理,并將守護(hù)標(biāo)志設(shè)置為true。 但是,如下所示,輸出結(jié)果會(huì)發(fā)生變化 -

import multiprocessing
import time

def nondaemonProcess():
   print("starting my Process")
   time.sleep(8)
   print("ending my Process")
def daemonProcess():
   while True:
   print("Hello")
   time.sleep(2)
if __name__ == '__main__':
   nondaemonProcess = multiprocessing.Process(target = nondaemonProcess)
   daemonProcess = multiprocessing.Process(target = daemonProcess)
   daemonProcess.daemon = True
   nondaemonProcess.daemon = False
   daemonProcess.start()
   nondaemonProcess.start()

執(zhí)行上面示例代碼,得到以下結(jié)果 -

starting my Process
ending my Process

輸出與守護(hù)進(jìn)程線(xiàn)程生成的輸出相比是不同的,因?yàn)闆](méi)有守護(hù)進(jìn)程模式的進(jìn)程有輸出。 因此,主程序結(jié)束后,守護(hù)進(jìn)程會(huì)自動(dòng)結(jié)束以避免運(yùn)行進(jìn)程的持久性。

在Python中終止進(jìn)程

可以使用terminate()方法立即終止或終止一個(gè)進(jìn)程。 在完成執(zhí)行之前,我們將使用此方法來(lái)終止在函數(shù)的幫助下創(chuàng)建的子進(jìn)程。

例子

import multiprocessing
import time
def Child_process():
   print ('Starting function')
   time.sleep(5)
   print ('Finished function')
P = multiprocessing.Process(target = Child_process)
P.start()
print("My Process has terminated, terminating main thread")
print("Terminating Child Process")
P.terminate()
print("Child Process successfully terminated")

輸出結(jié)果 -

My Process has terminated, terminating main thread
Terminating Child Process
Child Process successfully terminated

該輸出顯示程序在執(zhí)行使用Child_process()函數(shù)創(chuàng)建的子進(jìn)程之前終止。 這意味著子進(jìn)程已成功終止。

在Python中識(shí)別當(dāng)前進(jìn)程

操作系統(tǒng)中的每個(gè)進(jìn)程都具有稱(chēng)為PID的進(jìn)程標(biāo)識(shí)。 在Python中,可以借助以下命令找出當(dāng)前進(jìn)程的PID -

import multiprocessing
print(multiprocessing.current_process().pid)

例子
以下Python腳本示例用于找出主進(jìn)程的PID以及子進(jìn)程的PID -

import multiprocessing
import time
def Child_process():
   print("PID of Child Process is: {}".format(multiprocessing.current_process().pid))
print("PID of Main process is: {}".format(multiprocessing.current_process().pid))
P = multiprocessing.Process(target=Child_process)
P.start()
P.join()

執(zhí)行上面示例代碼,得到以下結(jié)果 -

PID of Main process is: 9401
PID of Child Process is: 9402

在子類(lèi)中使用進(jìn)程

可以通過(guò)對(duì)threading.Thread類(lèi)進(jìn)行子分類(lèi)來(lái)創(chuàng)建線(xiàn)程。 另外,還可以通過(guò)對(duì)multiprocessing.Process類(lèi)進(jìn)行子分類(lèi)來(lái)創(chuàng)建流程。 要在子類(lèi)中使用流程,需要考慮以下幾點(diǎn) -

  • 需要定義一個(gè)Process類(lèi)的新子類(lèi)。
  • 需要覆蓋_init_(self [,args])類(lèi)。
  • 需要重寫(xiě)run(self [,args])方法來(lái)實(shí)現(xiàn)Process類(lèi)
  • 需要通過(guò)調(diào)用start()方法來(lái)啟動(dòng)進(jìn)程。

參考以下代碼 -

import multiprocessing
class MyProcess(multiprocessing.Process):
   def run(self):
   print ('called run method in process: %s' %self.name)
   return
if __name__ == '__main__':
   jobs = []
   for i in range(5):
   P = MyProcess()
   jobs.append(P)
   P.start()
   P.join()

執(zhí)行上面示例代碼,得到以下代碼-

called run method in process: MyProcess-1
called run method in process: MyProcess-2
called run method in process: MyProcess-3
called run method in process: MyProcess-4
called run method in process: MyProcess-5

Python多處理模塊 - Pool類(lèi)

如果在Python應(yīng)用程序中討論簡(jiǎn)單的并行處理任務(wù),那么多處理模塊提供了Pool類(lèi)。 下面的Pool類(lèi)方法可以用來(lái)在主程序中創(chuàng)建多個(gè)子進(jìn)程。

apply()方法
該方法與ThreadPoolExecutorsubmit()方法類(lèi)似,直到結(jié)果準(zhǔn)備就緒。

apply_async()方法
當(dāng)需要并行執(zhí)行任務(wù)時(shí),需要使用apply_async()方法將任務(wù)提交給池。 這是一個(gè)異步操作,直到執(zhí)行完所有的子進(jìn)程之后才會(huì)鎖定主線(xiàn)程。

map()方法
就像apply()方法一樣,它也會(huì)阻塞直到結(jié)果準(zhǔn)備就緒。 它相當(dāng)于內(nèi)置的map()函數(shù),它將多個(gè)塊中的可迭代數(shù)據(jù)分開(kāi)并作為單獨(dú)的任務(wù)提交給進(jìn)程池。

map_async()方法
它是map()方法的一個(gè)變體,apply_async()apply()方法的變體。 它返回一個(gè)結(jié)果對(duì)象。 當(dāng)結(jié)果準(zhǔn)備就緒時(shí),就會(huì)應(yīng)用一個(gè)可調(diào)用對(duì)象。 可調(diào)用函數(shù)必須立即完成; 否則,處理結(jié)果的線(xiàn)程將被阻止。

例子

以下示例實(shí)現(xiàn)執(zhí)行并行執(zhí)行的進(jìn)程池。 通過(guò)multiprocessing.Pool方法應(yīng)用square()函數(shù),可以簡(jiǎn)單計(jì)算數(shù)字的平方。 然后使用pool.map()提交5,因?yàn)檩斎胧菑?code>0到4的整數(shù)列表。結(jié)果將被存儲(chǔ)在p_outputs中并被打印輸出結(jié)果 -

def square(n):
   result = n*n
   return result
if __name__ == '__main__':
   inputs = list(range(5))
   p = multiprocessing.Pool(processes = 4)
   p_outputs = pool.map(function_square, inputs)
   p.close()
   p.join()
   print ('Pool :', p_outputs)

執(zhí)行上面示例代碼,得到以下結(jié)果 -

Pool : [0, 1, 4, 9, 16]