web-dev-qa-db-ja.com

joblib.Parallelを使用するときにメインループを保護することが重要なのはなぜですか?

Joblibドキュメントには、次の警告が含まれています。

Windowsでは、joblib.Parallelを使用する場合、コードのメインループを保護してサブプロセスの再帰的な生成を回避することが重要です。つまり、次のようなコードを記述する必要があります。

import ....

def function1(...):
    ...

def function2(...):
    ...

... if __name__ == '__main__':
    # do stuff with imports and functions defined about
    ...

「if __name__ == ‘__main__」ブロックの外ではコードを実行しないでください。インポートと定義のみを実行してください。

最初は、これは、関数がjoblib.Parallelは、モジュールを再帰的に呼び出しました。これは、一般的には良い習慣でしたが、多くの場合は不要であることを意味します。ただし、これがWindowsのリスクになるだけの理由は理解できません。さらに、 この答え は、メインループを保護できなかったために、非常に単純な非再帰的な問題の場合よりもコードの実行が数倍遅くなることを示しているようです。

好奇心から、ウィンドウボックスのメインループを保護せずに、joblibドキュメントからの非常に単純な非常に単純なループの例を実行しました。端末を閉じるまで、次のエラーで端末がスパム送信されました。

ImportError: [joblib] Attempting to do parallel computing without protecting your import on a system that does not suppo
rt forking. To use parallel-computing in a script, you must protect you main loop using "if __name__ == '__main__'". Ple
ase see the joblib documentation on Parallel for more information

私の質問は、joblibのWindows実装では、どの場合でもメインループを保護する必要がありますか?

これが非常に基本的な質問である場合はお詫びします。私は並列化の世界に慣れていないので、いくつかの基本的な概念が欠けているだけかもしれませんが、この問題について明確に説明されている場所はどこにもありませんでした。

最後に、これは純粋に学術的なものであることに注意したい。このように自分のコードを書くことが 一般的には良い習慣 である理由を理解しており、joblibに関係なくこれを続けます。

20
Joe

Windowsにはfork()がないため、これが必要です。この制限があるため、Windowsは、子で親の状態を再作成するために、それが生成するすべての子プロセスで__main__モジュールを再インポートする必要があります。つまり、モジュールレベルで新しいプロセスを生成するコードがある場合、そのコードはすべての子プロセスで再帰的に実行されます。 if __name__ == "__main__"ガードは、モジュールスコープのコードが子プロセスで再実行されないようにするために使用されます。

does have fork()であるため、これはLinuxでは必要ありません。これにより、__main__モジュールを再インポートすることなく、親の同じ状態を維持する子プロセスをフォークできます。 。

23
dano