最後の目標は、バックグラウンドでメソッドを実行することですが、並列ではありません:複数のオブジェクトがこのメソッドを呼び出すときは、バックグラウンドでの実行を実現するには、サブプロセス(スレッドではない)でメソッドを実行しなければならず、spawn(forkではなく)を使用してメソッドを開始する必要があります。並列実行を防ぐために、明らかな解決策は、プロセス間で共有されるグローバルロックを設けることです。
次のコードの両方で強調表示されているように、Unixのデフォルトであるプロセスがforkされると、簡単に達成できます。
私たちは、クラス変数としてそれを共有することができますPython:生成されたプロセス間でロックを共有すること
import multiprocessing as mp
from time import sleep
class OneAtATime:
l = mp.Lock()
def f(self):
with self.l:
sleep(1)
print("Hello")
if __name__ == "__main__":
a = OneAtATime()
b = OneAtATime()
p1 = mp.Process(target = a.f)
p2 = mp.Process(target = b.f)
p1.start()
p2.start()
それともメソッドに渡すことができます:
import multiprocessing as mp
from time import sleep
class OneAtATime:
def f(self, l):
with l:
sleep(1)
print("Hello")
if __name__ == "__main__":
a = OneAtATime()
b = OneAtATime()
m = mp.Manager()
l = mp.Lock()
p1 = mp.Process(target = a.f, args = (l,))
p2 = mp.Process(target = b.f, args = (l,))
p1.start()
p2.start()
これらのコードのいずれもが1秒で「こんにちは」印刷の適切な行動を持っています間隔の。 しかし、start methodを 'スポーン'に変更すると、それらは壊れてしまいます。
最初の(1)は、両方の "hello"を同時に印刷します。これは、the internal state of a class is not pickledなので、同じロックを持たないからです。
2番目のファイル(2)は、実行時にFileNotFoundErrorで失敗します。私はそれがロックが漬けにされないという事実と関係していると思う:Python sharing a lock between processesを参照してください。
この回答では、2つの修正が提案されています(注:私は任意の数のプロセスをランダムに作成したいのでプールを使用できません)。
私は2番目の修正を適応させる方法を発見していないが、私は最初のものを実装してみました:
import multiprocessing as mp
from time import sleep
if __name__ == "__main__":
mp.set_start_method('spawn')
class OneAtATime:
def f(self, l):
with l:
sleep(1)
print("Hello")
if __name__ == "__main__":
a = OneAtATime()
b = OneAtATime()
m = mp.Manager()
l = m.Lock()
p1 = mp.Process(target = a.f, args = (l,))
p2 = mp.Process(target = b.f, args = (l,))
p1.start()
p2.start()
これははAttributeErrorとFileNotFoundError(3)で失敗します。実際には、forkメソッドが使用されているとき(BrokenPipe)も失敗します(4)。
スポーンされたプロセス間でロックを共有する適切な方法は何ですか?
私が番号をつけた4つの失敗の簡単な説明も良いでしょう。 私はArchlinuxでPython 3.6を実行しています。
ドキュメントをかなり慎重に読んだようです。 [17.2.1.5](https://docs.python.org/3.6/library/multiprocessing.html#sharing-state-between-processes)のソリューションを見てきましたか?ロックを共有メモリまたはマネージャーに入れることができるはずですか? –
私は試してみましたが、これは3番目のコードスニペットです。それは動作しませんでしたが、おそらくトリックを行うなど、これを行うための多くの方法があります。 – Zil0
申し訳ありませんが、私はコメントする前にコードをさらに研究していたはずです。 :-) –