web-dev-qa-db-ja.com

Python multiprocessing module:プロセスをタイムアウトで結合する

複雑なシミュレーションのパラメータの最適化を行っています。最適化アルゴリズムのパフォーマンスを向上させるためにマルチプロセッシングモジュールを使用しています。 http://pymotw.com/2/multiprocessing/basics.html で学んだマルチプロセッシングの基本。複雑なシミュレーションは、最適化アルゴリズムからの指定されたパラメーターに応じて、約1〜5分かかります。パラメータの選択が非常に悪い場合、シミュレーションは30分以上続く可能性があり、結果は役に立ちません。したがって、定義された時間よりも長く続くすべてのシミュレーションを終了する、マルチプロセッシングへのタイムアウトを組み込むことを考えていました。問題の抽象化されたバージョンを以下に示します。

_import numpy as np
import time
import multiprocessing

def worker(num):

    time.sleep(np.random.random()*20)

def main():

    pnum = 10    

    procs = []
    for i in range(pnum):
        p = multiprocessing.Process(target=worker, args=(i,), name = ('process_' + str(i+1)))
        procs.append(p)
        p.start()
        print 'starting', p.name

    for p in procs:
        p.join(5)
        print 'stopping', p.name

if __name__ == "__main__":
    main()
_

p.join(5)は、5秒のタイムアウトを定義しています。 forループ_for p in procs:_があるため、プログラムは最初のプロセスが完了するまで5秒間待機し、次に2番目のプロセスが完了するまで5秒間待機します。ただし、プログラムがそれより長く続くすべてのプロセスを終了するようにします。 5秒。さらに、どのプロセスも5秒より長く持続しない場合、プログラムはこの5秒待機してはなりません。

12
brp

これを行うには、タイムアウトの秒数を待機するループを作成し、すべてのプロセスが終了したかどうかを頻繁に確認します。割り当てられた時間内にすべてが完了しない場合は、すべてのプロセスを終了します。

TIMEOUT = 5 
start = time.time()
while time.time() - start <= TIMEOUT:
    if not any(p.is_alive() for p in procs):
        # All the processes are done, break now.
        break

    time.sleep(.1)  # Just to avoid hogging the CPU
else:
    # We only enter this if we didn't 'break' above.
    print("timed out, killing all processes")
    for p in procs:
        p.terminate()
        p.join()
10
dano

すべてのプロセスを強制終了したい場合は、マルチプロセッシングのプールを使用して、個々のタイムアウトではなく、すべての実行に対して一般的なタイムアウトを定義する必要があります。

import numpy as np
import time
from multiprocessing import Pool

def worker(num):
    xtime = np.random.random()*20
    time.sleep(xtime)
    return xtime

def main():

    pnum = 10
    pool = Pool()
    args = range(pnum)
    pool_result = pool.map_async(worker, args)

    # wait 5 minutes for every worker to finish
    pool_result.wait(timeout=300)

    # once the timeout has finished we can try to get the results
    if pool_result.ready():
        print pool_result.get(timeout=1)

if __name__ == "__main__":
    main()

これにより、すべてのワーカーの戻り値が順にリストされます。
詳細はこちら: https://docs.python.org/2/library/multiprocessing.html#module-multiprocessing.pool

11
Raiden Drake

ダノの助けのおかげで私は解決策を見つけました:

import numpy as np
import time
import multiprocessing

def worker(num):

    time.sleep(np.random.random()*20)

def main():

    pnum = 10    
    TIMEOUT = 5 
    procs = []
    bool_list = [True]*pnum

    for i in range(pnum):
        p = multiprocessing.Process(target=worker, args=(i,), name = ('process_' + str(i+1)))
        procs.append(p)
        p.start()
        print 'starting', p.name

    start = time.time()
    while time.time() - start <= TIMEOUT:
        for i in range(pnum):
            bool_list[i] = procs[i].is_alive()

        print bool_list

        if np.any(bool_list):  
            time.sleep(.1)  
        else:
            break
    else:
        print("timed out, killing all processes")
        for p in procs:
            p.terminate()

    for p in procs:
        print 'stopping', p.name,'=', p.is_alive()
        p.join()

if __name__ == "__main__":
    main()

最もエレガントな方法ではありません。bool_listを使用するよりも良い方法があると思います。 5秒のタイムアウト後もまだ生きているプロセスは強制終了されます。ワーカー関数でタイムアウトよりも短い時間を設定している場合、5秒のタイムアウトに達する前にプログラムが停止することがわかります。ある場合、私はまだよりエレガントな解決策を開いています:)

2
brp