Python 3.1。私の目標は、利用可能なすべてのプロセッサを100%使用することです。ただし、ここでのコードスニペットは30にしか達していません。 %-すべてのプロセッサーで50%。
とにかく 'force' pythonをすべて使用するためにありますか?OS(windows 7、64bit)はPythonのプロセッサへのアクセスを制限していますか?以下のコードスニペットの実行中に、タスクマネージャーは、プロセッサのスパイクを監視しますが、100%に到達して維持することはありません。それに加えて、途中で複数のpython.exeプロセスが作成および破棄されるのを確認できます。 4つのプロセスでは、各プロセスは独自のコアを使用していませんが、代わりにプロセスは何を使用していますか?すべてのコアを共有していますか?そうであれば、プロセスを強制的にコアを共有しているのはOSですか?
import multiprocessing
def worker():
#worker function
print ('Worker')
x = 0
while x < 1000:
print(x)
x += 1
return
if __== '__main__':
jobs = []
for i in range(50):
p = multiprocessing.Process(target=worker)
jobs.append(p)
p.start()
from multiprocessing import Process, Lock
def f(l, i):
l.acquire()
print('worker ', i)
x = 0
while x < 1000:
print(x)
x += 1
l.release()
if __== '__main__':
lock = Lock()
for num in range(50):
Process(target=f, args=(lock, num)).start()
すべてのコアを100%使用するには、新しいプロセスを作成および破棄しないでください。
コアごとにいくつかのプロセスを作成し、それらをパイプラインにリンクします。
OSレベルでは、すべてのパイプラインプロセスが同時に実行されます。
書く量が少ないほど(そしてOSに委任する量が多いほど)、できるだけ多くのリソースを使用する可能性が高くなります。
python p1.py | python p2.py | python p3.py | python p4.py ...
CPUを最大限に活用します。
psutil
to 各プロセスを固定multiprocessing
によって特定のCPUに生成されます:
import multiprocessing as mp
import psutil
def spawn():
procs = list()
n_cpus = psutil.cpu_count()
for cpu in range(n_cpus):
affinity = [cpu]
d = dict(affinity=affinity)
p = mp.Process(target=run_child, kwargs=d)
p.start()
procs.append(p)
for p in procs:
p.join()
print('joined')
def run_child(affinity):
proc = psutil.Process() # get self pid
print('PID: {pid}'.format(pid=proc.pid))
aff = proc.cpu_affinity()
print('Affinity before: {aff}'.format(aff=aff))
proc.cpu_affinity(affinity)
aff = proc.cpu_affinity()
print('Affinity after: {aff}'.format(aff=aff))
if __== '__main__':
spawn()
注:コメントどおり、 psutil.Process.cpu_affinity
はmacOSでは使用できません。
純粋なPythonの最小の例:
def f(x):
while 1:
# ---bonus: gradually use up RAM---
x += 10000 # linear growth; use exponential for faster ending: x *= 1.01
y = list(range(int(x)))
# ---------------------------------
pass # infinite loop, use up CPU
if __== '__main__': # name guard to avoid recursive fork on Windows
import multiprocessing as mp
n = mp.cpu_count() * 32 # multiply guard against counting only active cores
with mp.Pool(n) as p:
p.map(f, range(n))
使用法:寒い日にウォームアップする(ただし、ループを無意味なものに変更してください。)
警告:終了するには、プラグを抜かないで、または電源ボタンを押したまま、Ctrl-Cを押します。
コードスニペット1について:テストマシンにはいくつのコア/プロセッサがありますか? CPUコアが2つしかない場合、これらのプロセスのうち50個を実行しても効果はありません。実際、OSが実際の作業よりも多くの時間をコンテキストスイッチングに費やしてCPUのオンとオフを切り替える必要があります。
生成されるプロセスの数をコアの数に減らしてみてください。したがって、「for i in range(50):」は次のようになります。
import os;
# assuming you're on windows:
for i in range(int(os.environ["NUMBER_OF_PROCESSORS"])):
...
コードスニペット2については、一度に1つのプロセスのみが保持できるmultiprocessing.Lockを使用しているため、このバージョンのプログラムのすべての並列処理を完全に制限しています。プロセス1〜50が開始し、ランダムプロセス(プロセス7など)がロックを取得するように、ものをシリアル化しました。プロセス1〜6、および8〜50は、すべてライン上にあります。
l.acquire()
彼らがそこに座っている間、彼らはロックが解除されるのを待っています。 Lockプリミティブの実装に応じて、CPUを使用していない可能性があり、RAMなどのシステムリソースを使用してそこに座っていますが、CPUで有用な作業を行っていません。プロセス7カウントと1000に出力してからロックを解除します。OSは、残りの49個のプロセスの1つをランダムに実行します。最初に起動したプロセスは、次にロックを取得し、残りの48個がロックを待機します。プログラム全体を継続します。
基本的に、コードスニペット2は、同時実行を困難にする例です。多くのプロセスまたはスレッドによる共有リソースへのアクセスを管理する必要があります。ただし、この特定のケースでは、これらのプロセスが相互に待機する必要がある理由はありません。
したがって、これら2つのうち、スニペット1はCPUをより効率的に利用することに近いものです。コアの数と一致するようにプロセスの数を適切に調整すると、はるかに改善された結果が得られると思います。