Мы должны быть осторожны, чтобы сделать четкое различие между потоками и процессами.
Нити все работают в рамках одного процесса. Значения Доступ к может использоваться совместно между потоками. Значения могут быть изменены потоками в безопасном (скоординированном) порядке, только если значение защищено threading.Lock
до его изменения. В CPython, наиболее распространенной реализации Python, а также PyPy, но в отличие от других реализаций, таких как Jython или Iron Python, GIL (глобальная блокировка интерпретатора) предотвращает запуск более одного потока в любой момент времени. Таким образом, под CPython несколько потоков фактически запускаются серийно, а не одновременно. Тем не менее, несколько потоков могут быть полезны для интенсификации работы ввода-вывода, например, для запросов на многие веб-сайты, поскольку большая часть времени тратится на ожидание активности сети (I/O). Таким образом, множественные потоки не должны ждать столько же, сражаясь за доступ к одному процессору, по сравнению с задачами, которые являются CPU-интенсивными, как математические вычисления.
Теперь, сказав все это, вы имеете дело с несколькими процессами , а не потоками. Процессы независимы друг от друга. Они могут работать и выполняться одновременно на нескольких процессорах, если они доступны (в том числе под CPython). Когда вы создаете процесс, глобальные значения копируются из исходного процесса в порожденный процесс. На некоторых ОС, таких как Linux, которые имеют «копирование при записи», значения фактически разделяются между процессами до, процесс пытается перезаписать значение, и в это время значение копируется, чтобы стать независимым от другого процесса. Поэтому, когда вы меняете значения, , два процесса заканчиваются двумя переменными с одинаковыми именами, но могут иметь совершенно разные значения.
Для облегчения sharing state between processes имеются специальные объекты, предоставляемые модулем многопроцессорной обработки. К ним относятся mp.Value
, mp.Array
, mp.Manager
. Обратите внимание, что при использовании этих объектов за кулисами происходит блокировка, которая должна быть получена до того, как значения могут быть изменены. Это не позволяет процессу изменять значение, а другой процесс пытается сделать то же самое. Однако блокировка также замедляет процессы, потому что приходится ждать выхода блокировки.
Теперь, чтобы сигнализировать процесс, когда состояние было достигнуто в другом процессе, используют mp.Event
:
import multiprocessing as mp
import time
def Counter(i, event):
i.value=1
while i.value > 0 and not event.is_set():
print("i: ",i.value)
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)
event = mp.Event()
counter = mp.Process(target=Counter, args=(num, event))
counter.start()
tester = mp.Process(target=ValueTester, args=(num, 10, event))
tester.start()
tester.join()
counter.join()
print("Process Complete")
Дополнительные примеры о том, как использовать мультипроцессирование см Doug Hellman's Python Module of the Week tutorial.
Благодарим вас за объяснение, но я боюсь сказать, что ваш код, похоже, не работает для меня; он работает, но счетчик никогда не останавливается и продолжает работать бесконечно. Хотел бы я предложить улучшения/изменения, но это очень ново для меня! – FreeBixi
Если ваша машина очень быстрая, тогда 'ValueTester' может работать * до того, как' 'i.value' будет больше, чем' stopval'. В этом случае функция «ValueTester» заканчивается без установки события. Тогда 'Counter' может продолжаться бесконечно. Я изменю код, чтобы предотвратить это ... – unutbu
Это, кажется, работает сейчас, спасибо! Я не знал, что счетчик остановится в разных местах в зависимости от скорости вашего компьютера. – FreeBixi