#python #multiprocessing
#python #многопроцессорная обработка
Вопрос:
Я новичок в изучении python и столкнулся с некоторыми проблемами при использовании блокировок во время многопроцессорной обработки. Я получаю код выхода 0 и правильный ответ, но все еще получаю какое-то сообщение об ошибке, которое я действительно не до конца понимаю. Вот код, который я написал-
import time
import multiprocessing
def deposit(balance):
for i in range(100):
time.sleep(0.01)
lck.acquire()
balance.value = 1
lck.release()
def withdraw(balance):
for i in range(100):
time.sleep(0.01)
lck.acquire()
balance.value -= 1
lck.release()
if __name__ == '__main__':
balance = multiprocessing.Value('i', 200)
lck = multiprocessing.Lock()
d = multiprocessing.Process(target=deposit, args=(balance,))
w = multiprocessing.Process(target=withdraw, args=(balance,))
d.start()
w.start()
d.join()
w.join()
print(balance.value)
и вот ошибка, которую я получаю
`Process Process-1:
Traceback (most recent call last):
File "C:UsersrahulAppDataLocalProgramsPythonPython39libmultiprocessingprocess.py", line
315, in _bootstrap
self.run()
File "C:UsersrahulAppDataLocalProgramsPythonPython39libmultiprocessingprocess.py", line
108, in run
self._target(*self._args, **self._kwargs)
File "C:UsersrahulPycharmProjectspythonProjectLearningPython.py", line 10, in deposit
lck.acquire()
NameError: name 'lck' is not defined
Process Process-2:
Traceback (most recent call last):
File "C:UsersrahulAppDataLocalProgramsPythonPython39libmultiprocessingprocess.py", line
315, in _bootstrap
self.run()
File "C:UsersrahulAppDataLocalProgramsPythonPython39libmultiprocessingprocess.py", line
108, in run
self._target(*self._args, **self._kwargs)
File "C:UsersrahulPycharmProjectspythonProjectLearningPython.py", line 17, in withdraw
lck.acquire()
NameError: name 'lck' is not defined
200
Процесс завершен с кодом выхода 0
Ответ №1:
Проблема здесь в том, что lck
это выходит за рамки ваших дочерних процессов. Глобальные переменные не являются общими для всех процессов. Попробуйте передать блокировку в процессы.
В качестве альтернативы используйте потоки, как предложено в ответе Кана. Они намного дружелюбнее и в этом случае все еще работают нормально.
import time
import multiprocessing
def deposit(balance,lck):
for i in range(100):
time.sleep(0.01)
lck.acquire()
balance.value = 1
lck.release()
def withdraw(balance,lck):
for i in range(100):
time.sleep(0.01)
lck.acquire()
balance.value -= 1
lck.release()
if __name__ == '__main__':
balance = multiprocessing.Value('i', 200)
lck = multiprocessing.Lock()
d = multiprocessing.Process(target=deposit, args=(balance,lck))
w = multiprocessing.Process(target=withdraw, args=(balance,lck))
d.start()
w.start()
d.join()
w.join()
print(balance.value)
Комментарии:
1. Это правильное решение. Блокировка создается только в основном процессе и передается дочерним процессам в качестве аргумента.
Ответ №2:
Потому deposit
что и withdraw
запускаются в других процессах.По их мнению, процесс не __main__
выполняется, поэтому if
оператор не выполняется и lck
не определен.
Попробуйте выполнить
import os
import multiprocessing
def deposit(balance):
print(os.getpid(),__name__)
def withdraw(balance):
print(os.getpid(),__name__)
if __name__ == '__main__':
print(os.getpid(), __name__)
balance = multiprocessing.Value('i', 200)
lck = multiprocessing.Lock()
d = multiprocessing.Process(target=deposit, args=(balance,))
w = multiprocessing.Process(target=withdraw, args=(balance,))
d.start()
w.start()
d.join()
w.join()
В моем случае это показывает
19604 __main__
33320 __mp_main__
45584 __mp_main__
Ваш код может выполняться, если вы поместите lck = multiprocessing.Lock()
outside if
.Но я уверен, что это не то, что вы хотите.
threading
В этом случае вы должны использовать multiprocess
вместо и посмотреть на разницу между многопоточностью и многопроцессорностью.
Комментарии:
1. Размещение
lck = multiprocessing.Lock()
внеif
будет создавать разные блокировки в каждом процессе. Создайте одну блокировку внутриif
и передайте ее в качестве аргумента другим процессам, чтобы они использовали одну и ту же блокировку.2. ДА. Вот почему я сказал
I'm sure it's not what you want.
. И ваш способ тоже работает. Но, учитывая, что он, похоже, не находится в ситуации, которая сильно нуждается в многопроцессорной обработке, я все же предлагаю использоватьthreading
вместо этого, которые не нужно передаватьlck
везде.3. @MarkTolonen:забудьте использовать at . И на самом деле ему нужно передать все общие переменные, а не только
lck
.4.
threading
полезен только для параллелизма, связанного с вводом-выводом, или для вызова других языков, которые освобождают GIL (например, viactypes
). GIL предотвращает получение каких-либо преимуществ в потоковой обработке только для Python. Этот упрощенный пример на самом деле не увеличивает скорость ни при использовании потоков, ни при многопроцессорной обработке, но это упражнение в правильном использовании многопроцессорной обработки.5. @MarkTolonen: я считаю
threading
, что это также полезно для простой ситуации, когда скорость не вызывает беспокойства. Но да, это может быть упражнение в многопроцессорной обработке, или многопоточности, или что угодно.