1. 程式人生 > 程式設計 >Python使用多程序執行含有任意個引數的函式

Python使用多程序執行含有任意個引數的函式

1. 問題引出

許多時候,我們對程式的速度都是有要求的,速度自然是越快越好。對於Python的話,一般都是使用multiprocessing這個庫來實現程式的多程序化,例如:

我們有一個函式my_print,它的作用是列印我們的輸入:

def my_print(x):
print(x)

但是我們嫌它的速度太慢了,因此我們要將這個程式多程序化:

from multiprocessing import Pool
 
def my_print(x):
  print(x)
 
if __name__ == "__main__":
  x = [1,2,3,4,5]
  pool = Pool()
  pool.map(my_print,x)
  pool.close()
  pool.join()

很好,現在速度與之前的單程序相比提升非常的快,但是問題來了,如果我們的引數不只有一個x,而是有多個,這樣能行嗎?比如現在my_print新增一個引數y:

def my_print(x,y):
print(x + y)

檢視pool.map的函式說明:

def map(self,func,iterable,chunksize=None):
  '''
  Apply `func` to each element in `iterable`,collecting the results
  in a list that is returned.
  '''
  return self._map_async(func,mapstar,chunksize).get()

發現函式的引數是作為iter傳進去的,但是我們現在有兩個引數,自然想到使用zip將引數進行打包:

if __name__ == "__main__":
  x = [1,5]
  y = [1,1,1]
  zip_args = list(zip(x,y))
  pool = Pool()
  pool.map(my_print,zip_args)
  pool.close()
  pool.join()

可是執行後卻發現,y引數並沒有被傳進去:

Python使用多程序執行含有任意個引數的函式

那麼如何傳入多個引數呢?這也就是本文的重點,接著往下看吧。

2. 解決方案

2.1 使用偏函式(partial)

偏函式有點像數學中的偏導數,可以讓我們只關注其中的某一個變數而不考慮其他變數的影響。上面的例子中,Y始終等於1,那麼我們在傳入引數的時候,只需要考慮X的變化即可。

例如你有一個函式,該函式有兩個引數a,b,a是不同路徑的下的圖片的路徑,b是輸出的路徑。很明顯,a是一直在變化的,但是因為我們要將所有圖片儲存在同一個資料夾下,那麼b很可能一直都沒變。

具體如下:

if __name__ == '__main__':# 多執行緒,多引數,partial版本
  x = [1,5]
  y = 1
 
  partial_func = partial(my_print,y=y)
  pool = Pool()
  pool.map(partial_func,x)
  pool.close()
  pool.join()

2.2 使用可變引數

在Python函式中,函式可以定義可變引數。顧名思義,可變引數就是傳入的引數個數是可變的,可以是1個、2個到任意個,這就直接給我們提供了一種思路。具體如下:

def multi_wrapper(args):
  return my_print(*args)
 
def my_print(x,y):
  print(x + y)
if __name__ == "__main__": # 多執行緒,多引數,可變引數版本
  x = [1,y))
 
  pool = Pool()
  pool.map(multi_wrapper,zip_args)
  pool.close()
  pool.join()

2.3 使用pathos提供的多程序庫

from pathos.multiprocessing import ProcessingPool as newPool
 
if __name__ == '__main__':# 多執行緒,多引數,pathos版本
  x = [1,1]
 
  pool = newPool()
  pool.map(my_print,x,y)
  pool.close()
  pool.join()

在該庫的map函式下,可以看到,它允許多引數輸入,其實也就是使用了可變引數:

def map(self,f,*args,**kwds):
  AbstractWorkerPool._AbstractWorkerPool__map(self,**kwds)
  _pool = self._serve()
  return _pool.map(star(f),zip(*args)) # chunksize

2.4 使用starmap函式

if __name__ == '__main__': # 多執行緒,多引數,starmap版本
  x = [1,1]
 
  zip_args = list(zip(x,y))
  pool = Pool()
  pool.starmap(my_print,zip_args)
  pool.close()
  pool.join()

3. 總結

其實在以上4種實現方法中 ,第1種方法的限制較多,如果該函式的其它引數都在變化的話,那麼它就不能很好地工作,而剩下的方法從體驗上來講是依次遞增的,它們都可以接受任意多引數的輸入,但是第2種需要額外寫一個函式,扣分;第3種方法需要額外安裝pathos包,扣分;而最後一種方法不需要任何額外不擇就可以完成,所以,推薦大家選擇第4種方法!

以上這篇Python使用多程序執行含有任意個引數的函式就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。