Многопроцессорный пул Python.imap выдает ошибку ValueError: list.remove(x): x отсутствует в списке

#python #python-2.7 #python-multiprocessing #python-unittest

#python #python-2.7 #python-многопроцессорная обработка #python-unittest

Вопрос:

У меня есть очень простой тестовый инструмент, который создает и закрывает тестовый класс ‘APMSim’ в разных потоках, класс не может быть выбран, поэтому я должен использовать многопроцессорный Pool.imap, чтобы избежать их передачи между процессами:

 class APMSimFixture(TestCase):

    def setUp(self):
        self.pool = multiprocessing.Pool()
        self.sims = self.pool.imap(
            apmSimUp,
            range(numCores)
        )

    def tearDown(self):
        self.pool.map(
            simDown,
            self.sims
        )

    def test_empty(self):
        pass
 

Однако, когда я запускаю пустой модуль Python, я сталкиваюсь со следующей ошибкой:

 Error
Traceback (most recent call last):
  File "/home/peng/git/datapassport/spookystuff/mav/pyspookystuff_test/mav/__init__.py", line 87, in tearDown
    self.sims
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 251, in map
    return self.map_async(func, iterable, chunksize).get()
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 567, in get
    raise self._value
 

Почему это может произойти? Есть ли исправление для этого?

Ответ №1:

multiprocessing повторно вызывает исключение из вашей рабочей функции / дочернего процесса в родительском процессе, но при передаче от дочернего к родительскому процессу он теряет трассировку. Проверьте свою рабочую функцию, именно этот код идет не так. Это может помочь взять любую вашу рабочую функцию и изменить:

 def apmSimUp(...):
    ... body ...
 

Для:

 import traceback

def apmSimUp(...):
    try:
        ... body ...
    except:
        traceback.print_exc()
        raise
 

Это явно выводит полную исходную трассировку исключения (затем позволяет ему нормально распространяться), чтобы вы могли видеть, в чем настоящая проблема.

Комментарии:

1. Большое спасибо! Но это также означает, что многопроцессорная обработка — это плохо разработанная библиотека. Хорошая библиотека не будет скрывать информацию об ошибках

2. Кроме того, поскольку этот блок используется так много раз, я хотел бы сделать его аннотацией функции, но при этом теряется возможность выбора функции, есть ли способ сделать его кратким и одновременно отображать информацию об ошибках?

3. @tribbloid: Нетривиально пересылать полную информацию стека от дочернего элемента к родительскому, но я думаю, что в Py3 это действительно может исправить; используйте 7-летний Python, вы получите больше причуд. Вы могли бы немного обмануть бит аннотации и просто передать функцию в качестве аргумента оболочке; map(mywrapper, zip(itertools.repeat(realfunc), origarguments)) , где mywrapper просто есть тело try блока, содержащее realfunc, arg = args , realfunc(arg) .