したがって、私が作成しているアルゴリズムがあり、関数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
が返されたデータをどのように処理するかはわかりません。
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
機能を提供することです。
これは 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)