[930]python平行計算框架pathos模組

周小董發表於2020-12-09

應用python進行資料探勘或計算時,往往需要遍歷多種引數進行資料建模,而單次的建模或計算有時候非常耗時,這時候可以利用python的平行計算功能,加快計算速度。

python能夠應用平行計算的模組有多個multiprocessing、pathos等。其中multiprocessing模組應用的較多,但對於資料探勘場景來說,pathos模組更實用,尤其允許輸入多個可變引數非常簡單實用。

1.環境&軟體

  • win10 64bit
  • Python 3.7

2.功能實現

本文總結整理了常見的平行計算場景,編寫parallel.py模組,主要利用pathos模組實現,可以實現單變數並行、多變數並行、並行巢狀等功能。通過tdqm模組增加了進度條,可以顯示計算進度等資訊,通過functools模組中的partial函式將靜態引數凍結,以適應並行框架。

  • 安裝
pip install pathos
  • parallel.py
# -*- coding:utf-8 -*-
import time
from functools import partial
from pathos.pools import ProcessPool, ThreadPool
from tqdm import tqdm


def parallel(func, *args, show=False, thread=False, **kwargs):
    """
    平行計算
    :param func: 函式,必選引數
    :param args: list/tuple/iterable,1個或多個函式的動態引數,必選引數
    :param show:bool,預設False,是否顯示計算進度
    :param thread:bool,預設False,是否為多執行緒
    :param kwargs:1個或多個函式的靜態引數,key-word形式
    :return:list,與函式動態引數等長
    """

    # 凍結靜態引數
    p_func = partial(func, **kwargs)
    # 開啟程式/執行緒池
    pool = ThreadPool() if thread else ProcessPool()
    try:
        if show:
            start = time.time()
            # imap方法
            with tqdm(total=len(args[0]), desc="計算進度") as t:  # 進度條設定
                r = []
                for i in pool.imap(p_func, *args):
                    r.append(i)
                    t.set_postfix({'並行函式': func.__name__, "計算花銷": "%ds" % (time.time() - start)})
                    t.update()
        else:
            # map方法
            r = pool.map(p_func, *args)
        return r
    except Exception as e:
        print(e)
    finally:
        # 關閉池
        pool.close()  # close the pool to any new jobs
        pool.join()  # cleanup the closed worker processes
        pool.clear()  # Remove server with matching state

函式parallel的引數定義順序需要注意:必選引數–任意位置引數–預設引數–任意關鍵字引數

3.結果展示

定義另一個parallel_main.py模組,用來展示各個場景下平行計算結果。

  • parallel_main.py
# -*- coding:utf-8 -*-
from parallel import parallel


class A:
    @staticmethod
    def f1(x):
        return x + 1

    @staticmethod
    def f2(x, y):
        return x + y

    @staticmethod
    def f3(x, y, p=100):
        return x + y + p

    @staticmethod
    def f4(x):
        import time
        time.sleep(1)
        return x + 1

    def f5(self, x):
        r = parallel(self.f1, [1, 2, 3], thread=True)  # [2,3,4]
        return x + sum(r)

    def f6(self, x):
        r1 = parallel(self.f1, [1, 2, 3], thread=True)  # [2,3,4]
        r2 = parallel(self.f2, [1, 2, 3], r1, thread=True)  # [3,5,7]
        return x + sum(r2)


if __name__ == '__main__':
    f = A()
    print("f1計算結果(單引數並行模式):", parallel(f.f1, [1, 2, 3]), "\n", "#" * 50)
    print("f2計算結果(多引數並行模式):", parallel(f.f2, [1, 2, 3], [4, 5, 6]), "\n", "#" * 50)
    print("f3計算結果(多引數並行+函式引數模式):", parallel(f.f3, [1, 2, 3], [4, 5, 6], p=200), "\n", "#" * 50)
    print("f4計算結果(進度顯示):", parallel(f.f4, range(100), show=True), "\n", "#" * 50)
    print("f5計算結果(2層巢狀並行模式):", parallel(f.f5, range(10)), "\n", "#" * 50)
    print("f6計算結果(多層巢狀並行模式):", parallel(f.f6, range(10)), "\n", "#" * 50)

執行parallel_main.py檔案,結果如下:

image

4.總結&歸納

parallel函式使用注意點:

(1)函式至少輸入一個被並行函式,和可迭代序列引數

(2)要顯示計算過程,設定show=True

(3)被並行函式的依賴模組需要匯入,否則報NameError

(4)巢狀並行需要匯入parallel模組,且子並行需要設定為多執行緒模式(thread=True)

來源:https://zhuanlan.zhihu.com/p/102451932

相關文章