web-dev-qa-db-ja.com

複数のコアでPython

私は、終了するのにかなり長い時間がかかる(かなり大きな)プログラムを作成し、プログラムを高速化する方法を検討し始めました。

プログラムの実行中にタスクマネージャを開くと、1つのコアしか使用されていないことがわかりました。

いくつかの調査の後、私はこのウェブサイトを見つけました: numpyをインポートした後、マルチプロセッシングが単一コアのみを使用するのはなぜですか?os.system("taskset -p 0xff %d" % os.getpid())のソリューションを提供しますが、これは私にとっては機能しません、そして私のプログラムはシングルコアで動作し続けます。

次にこれを見つけました: is python複数のコアで実行できますか? 、これはマルチプロセッシングの使用を指しています。

したがって、マルチプロセッシングを調べた後、それを使用する方法についてこのドキュメンタリーに遭遇しました https://docs.python.org/3/library/multiprocessing.html#examples

私はコードを試しました:

from multiprocessing import Process

def f(name):
    print('hello', name)

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()

a = input("Finished")

(IDLEではなく)コードを実行した後、次のように述べられています。

Finished
hello bob
Finished

注:最初にEnterキーを押したときに「完了」と表示された後

この後、私はさらに混乱し、2つの質問があります

最初:それはまだ複数のコアで動作しません(私は8コアIntel i7を持っています)

2番目:ifステートメントコードを実行する前に「Finished」と入力するのはなぜですか(まだ終了していないのです!)

8

2番目の質問に最初に答えるには、a = input("Finished")if __name__ == '__main__':コードブロックの外にあるため、「終了」がターミナルに出力されます。したがって、これはモジュールが最初に読み込まれたときに割り当てられ、モジュール内のコードが実行される前に実行されるモジュールレベルの定数です。

最初の質問に答えるために、実行するプロセスを1つだけ作成し、続行する前に完了するまで待機しました。これにより、マルチプロセッシングの利点がなくなり、新しいプロセスを作成するオーバーヘッドが発生します。

複数のプロセスを作成するため、ある種のコレクション(pythonリストなど)を介してプールを作成し、すべてのプロセスを開始する必要があります。

実際には、プロセッサの数よりも多くを考慮する必要があります(使用可能なメモリの量、クラッシュしたワーカーを再起動する機能など)。ただし、これは上記のタスクを完了する簡単な例です。

import datetime as dt
from multiprocessing import Process, current_process
import sys

def f(name):
    print('{}: hello {} from {}'.format(
        dt.datetime.now(), name, current_process().name))
    sys.stdout.flush()

if __name__ == '__main__':
    worker_count = 8
    worker_pool = []
    for _ in range(worker_count):
        p = Process(target=f, args=('bob',))
        p.start()
        worker_pool.append(p)
    for p in worker_pool:
        p.join()  # Wait for all of the workers to finish.

    # Allow time to view results before program terminates.
    a = input("Finished")  # raw_input(...) in Python 2.

また、ワーカーを開始した直後に参加した場合、各ワーカーがタスクを完了するのを待ってから、次のワーカーを開始することにも注意してください。タスクの順序が連続的でなければならない場合を除き、これは一般的に望ましくありません。

通常は間違っています

worker_1.start()
worker_1.join()

worker_2.start()  # Must wait for worker_1 to complete before starting worker_2.
worker_2.join()

通常望ましい

worker_1.start()
worker_2.start()  # Start all workers.

worker_1.join()
worker_2.join()   # Wait for all workers to finish.

詳細については、次のリンクを参照してください。

12
Alexander