Создание переменной, которую можно сравнить между процессами - PullRequest
2 голосов
/ 02 ноября 2011

У меня есть код, подобный следующему,

class _Process(multiprocessing.Process):

    STOP = multiprocessing.Manager().Event()

    def __init__(self, queue, process_fn):

        self._q = queue
        self._p = process_fn
        super().__init__()

    def run(self):

        while True:
            dat = self._q.get()
            if not dat is _Process.STOP:
                self._p(dat, self._q)
                self._q.task_done()
            else:
                self._q.task_done()
                break

, но я не могу сравнить STOP успешно.Это не удивительно, когда я использую is, так как, я полагаю, is сравнивает идентификаторы объекта и из документов "... Это адрес объекта в памяти." Итак, поскольку я использую несколько процессов, адрес памяти будет другим.(Хотя я не могу сравнить его с ==, и я не уверен, почему это так.)

Это происходит с любым объектом, который я создаю с Manager(), но если я использую "true""Синглтон (True или False или None) это работает.Хотя это не подходящее решение, так как любое из этих значений может быть допустимым в очереди.

Так как же мне создать переменную, например синглтоны, которую можно сравнивать в разных процессах?

(NB. Я тоже пытался использовать выделенный класс, но получаю ошибки о том, что его невозможно мариновать.)

Обновление: Ответ, похоже, заключается в использовании класса, но яполучал проблемы с засолкой, так как я пробовал только с внутренним классом.Перемещение его в область видимости модуля исправило ошибку, и она работает нормально.- Спасибо @Schnouki!


Вот пример (и бессмысленный) использования кода, который показывает ошибку ...

def f(data, queue):
    print(data)

q = multiprocessing.JoinableQueue()

for i in range(4):
    p = _Process(q, f)
    p.daemon = True
    p.start()
    q.put(i)

q.join()

for i in range(4):
    q.put(_Process.STOP)

q.join()

1 Ответ

3 голосов
/ 02 ноября 2011

Это странный способ использования объекта Event ... Если вы не можете использовать None или логическое значение, я предлагаю вам использовать выделенный класс и проверить тип того, что вы получаете из очереди:

class StopProcessing(object):
    pass

#...

q.put(StopProcessing())

#...

while True:
    dat = self._q.get()
    if type(dat) is StopProcessing:
        # ...

Или, конечно, вы можете просто продолжать использовать multiprocessing.Event и проверять его тип. Однако это, вероятно, будет вводить в заблуждение, если кто-то еще читает ваш код; использование выделенного типа кажется мне намного чище и Pythonic.

РЕДАКТИРОВАТЬ: Хорошо, так что, очевидно, это не сработает, потому что новый класс не может быть выбран. Итак, вот еще одна идея: что, если вы прямо поместите тип в свою очередь, например так:

class StopProcessing(object):
    pass
#...
q.put(StopProcessing)
#...
while True:
    dat = self._q.get()
    if dat is StopProcessing:
        #...

Согласно документу pickle doc , «классы, которые определены на верхнем уровне модуля» могут быть засечены.

...