Ошибка при использовании блокировок в многопроцессорной обработке в Python

#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 (например, via ctypes ). GIL предотвращает получение каких-либо преимуществ в потоковой обработке только для Python. Этот упрощенный пример на самом деле не увеличивает скорость ни при использовании потоков, ни при многопроцессорной обработке, но это упражнение в правильном использовании многопроцессорной обработки.

5. @MarkTolonen: я считаю threading , что это также полезно для простой ситуации, когда скорость не вызывает беспокойства. Но да, это может быть упражнение в многопроцессорной обработке, или многопоточности, или что угодно.