ここでは、スレッドとプロセスを明確に区別するように注意する必要があります。
スレッドはすべて同じプロセスで動作します。アクセスされる値は、スレッド間で共有できます。値がスレッドによって保護されている場合にのみ、安全な (調整された) 方法でスレッドによって値を変更できます。threading.Lock
変更前です。Python と PyPy の最も一般的な実装である CPython では、Jython や Iron Python などの他の実装とは対照的に、GIL (グローバル インタープリター ロック) によって複数のスレッドが同時に実行されるのを防ぎます。そのため、CPython では、複数のスレッドが実際には同時にではなくシリアルに実行されます。それでも、ネットワーク (I/O) アクティビティの待機に多くの時間が費やされるため、多くの Web サイトのクエリなど、I/O を多用する作業には複数のスレッドが役立ちます。したがって、数学的計算のように CPU を集中的に使用するタスクと比較して、複数のスレッドが 1 つの CPU へのアクセスを争って待機する必要はありません。
以上のことをすべて言ったので、スレッドではなく、複数のプロセスを扱っています。プロセスは互いに独立しています。利用可能であれば、複数の CPU で同時に実行できます (CPython を含む)。プロセスを生成すると、グローバル値が元のプロセスから生成されたプロセスにコピーされます。Linux などの一部の OS では、「copy-on-write」を備えているため、プロセスが値を上書きしようとするまで、値は実際にはプロセス間で共有されます。その時点で値はコピーされ、他のプロセスから独立します。したがって、値を変更すると、2 つのプロセスは同じ名前の 2 つの変数になりますが、まったく異なる値を持つことができます。
プロセス間で状態を共有しやすくするために、マルチプロセッシング モジュールによって提供される特別なオブジェクトがあり
ます。これらには、、、が含まmp.Value
れmp.Array
ます
mp.Manager
。これらのオブジェクトを使用するとき
は、別のプロセスが同じことをしようとしている間に、あるプロセスが値を変更するのを防ぐためにa も使用する必要があることに注意してください。mp.Lock
ただし、ロックが解除されるまで待機する必要があるため、ロックもプロセスを遅くします。
別のプロセスで条件に達したときにプロセスにシグナルを送るには、次を使用しますmp.Event
。
import multiprocessing as mp
import time
def Counter(i, event, lock):
with lock:
i.value = 1
while i.value > 0 and not event.is_set():
print("i: ", i.value)
with lock:
i.value += 1
def ValueTester(i, stopval, event):
while True:
if i.value >= stopval:
event.set()
break
else:
time.sleep(0.1)
if __name__ == '__main__':
num = mp.Value('d', 0.0)
# A lock is not absolutely necessary here since only one process modifies
# num, but I'm including it since it is necessary (to avoid race conditions)
# in the more usual case when multiple processes may modify num.
lock = mp.Lock()
event = mp.Event()
counter = mp.Process(target=Counter, args=(num, event, lock))
counter.start()
tester = mp.Process(target=ValueTester, args=(num, 10, event))
tester.start()
tester.join()
counter.join()
print("Process Complete")
マルチプロセッシングの使用例については、Doug Hellman の Python Module of the Week チュートリアル を参照してください。