web-dev-qa-db-ja.com

Python multiprocessing:プールまたはプロセスの使用方法を知るには?

したがって、私が作成しているアルゴリズムがあり、関数multiprocessは、CPUと同じ数のプロセスで並列に別の関数CreateMatrixMp()を呼び出すことになっています。私はこれまでにマルチプロセッシングを行ったことがなく、以下の方法のどれがより効率的であるかはわかりません。関数CreateMatrixMp()のコンテキストで使用される「効率的な」という言葉は、何千回も呼び出される可能性がある必要があります。python multiprocessingモジュール、そしてこれら2つの可能性に来ています:

まず、Poolクラスを使用します。

_def MatrixHelper(self, args):
    return self.CreateMatrix(*args)

def Multiprocess(self, sigmaI, sigmaX):

    cpus = mp.cpu_count()
    print('Number of cpu\'s to process WM: %d' % cpus)
    poolCount = cpus*2
    args = [(sigmaI, sigmaX, i) for i in range(self.numPixels)]

    pool = mp.Pool(processes = poolCount, maxtasksperchild= 2)
    tempData = pool.map(self.MatrixHelper, args)
    pool.close()
    pool.join()
_

次に、Processクラスを使用します。

_def Multiprocess(self, sigmaI, sigmaX):

    cpus = mp.cpu_count()
    print('Number of cpu\'s to process WM: %d' % cpus)

    processes = [mp.Process(target = self.CreateMatrixMp, args = (sigmaI, sigmaX, i,)) for i in range(self.numPixels)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()
_

Poolがより良い選択のようです。オーバーヘッドが少ないことを確認しました。また、Processはマシン上のCPUの数を考慮しません。唯一の問題は、この方法でPoolを使用するとエラーが発生し、修正するたびにその下に新しいエラーが発生することです。 Processの方が実装しやすいように思われますが、私にとっては、それがより良い選択であると私は知っています。あなたの経験は何を教えてくれますか?

Poolを使用する必要がある場合、map()を選択するのは正しいですか?順序が維持されることが好ましいでしょう。 map関数はすべてのプロセスの結果のリストを返すことになっているので、私はtempData = pool.map(...)を持っています。 Processが返されたデータをどのように処理するかはわかりません。

15
Anonymous

Poolクラスの方が通常は便利だと思いますが、結果を順序付けするか、順序付けしないかによって異なります。

4つのランダムな文字列を作成したいとします(たとえば、ランダムなユーザーIDジェネレーターなどが考えられます)。

import multiprocessing as mp
import random
import string

# Define an output queue
output = mp.Queue()

# define a example function
def Rand_string(length, output):
    """ Generates a random string of numbers, lower- and uppercase chars. """
    Rand_str = ''.join(random.choice(
                    string.ascii_lowercase
                    + string.ascii_uppercase
                    + string.digits)
               for i in range(length))
    output.put(Rand_str)

# Setup a list of processes that we want to run
processes = [mp.Process(target=Rand_string, args=(5, output)) for x in range(4)]

# Run processes
for p in processes:
    p.start()

# Exit the completed processes
for p in processes:
    p.join()

# Get process results from the output queue
results = [output.get() for p in processes]

print(results)

# Output
# ['yzQfA', 'PQpqM', 'SHZYV', 'PSNkD']

ここでは、順序はおそらく問題ではありません。より良い方法があるかどうかはわかりませんが、関数が呼び出された順序で結果を追跡したい場合は、通常、最初のアイテムとしてIDを持つタプルを返します。たとえば、

# define a example function
def Rand_string(length, pos, output):
    """ Generates a random string of numbers, lower- and uppercase chars. """
    Rand_str = ''.join(random.choice(
                    string.ascii_lowercase
                    + string.ascii_uppercase
                    + string.digits)
                for i in range(length))
    output.put((pos, Rand_str))

# Setup a list of processes that we want to run
processes = [mp.Process(target=Rand_string, args=(5, x, output)) for x in range(4)]

print(processes)

# Output
# [(1, '5lUya'), (3, 'QQvLr'), (0, 'KAQo6'), (2, 'nj6Q0')]

これで、結果を並べ替えることができます。

results.sort()
results = [r[1] for r in results]
print(results)

# Output:
# ['KAQo6', '5lUya', 'nj6Q0', 'QQvLr']

プールクラス

さてあなたの質問へ:これはPoolクラスとどう違うのですか?通常はPool.mapタプルを作成してIDでソートするというフープを経由せずに、結果の順序付けられたリストを返す。したがって、通常はより効率的です。

def cube(x):
    return x**3

pool = mp.Pool(processes=4)
results = pool.map(cube, range(1,7))
print(results)

# output:
# [1, 8, 27, 64, 125, 216]

同様に、「適用」方法もあります。

pool = mp.Pool(processes=4)
results = [pool.apply(cube, args=(x,)) for x in range(1,7)]
print(results)

# output:
# [1, 8, 27, 64, 125, 216]

両方とも Pool.applyおよびPool.mapは、プロセスが完了するまでメインプログラムをロックします。

これで、Pool.apply_asyncおよびPool.map_asyncは、プロセスが完了するとすぐに結果を返します。これは、上記のProcessクラスと基本的に同じです。利点は、Pythonの組み込みapplyおよびmapからわかる便利なapplyおよびmap機能を提供することです。

16
user2489252

これは pypeln で簡単に実行できます。

import pypeln as pl

stage = pl.process.map(
    CreateMatrixMp, 
    range(self.numPixels), 
    workers=poolCount, 
    maxsize=2,
)

# iterate over it in the main process
for x in stage:
   # code

# or convert it to a list
data = list(stage)
1
Cristian Garcia