Как разделить строку между несколькими процессами с помощью Managers () в Python?

Мне нужно прочитать строки, написанные экземплярами multiprocessing.Process из основного процесса. Я уже использую менеджеры и очереди для передачи аргументов процессам, поэтому использование менеджеров кажется очевидным, , но менеджеры не поддерживают строки:

Менеджер, возвращаемый Manager (), будет поддерживать типы list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Queue, Value и Array.

Как передать состояние, представленное строкой, с помощью менеджеров из модуля многопроцессорности?


person Bengt    schedule 22.01.2014    source источник


Ответы (2)


менеджеры multiprocessing могут хранить значения, которые, в свою очередь, могут содержать экземпляры введите c_char_p из модуля ctypes:

>>> import multiprocessing
>>> import ctypes
>>> v = multiprocessing.Value('c', "Hello, World!")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/multiprocessing/__init__.py", line 253, in Value
    return Value(typecode_or_type, *args, **kwds)
  File "/usr/lib/python2.7/multiprocessing/sharedctypes.py", line 99, in Value
    obj = RawValue(typecode_or_type, *args)
  File "/usr/lib/python2.7/multiprocessing/sharedctypes.py", line 73, in RawValue
    obj.__init__(*args)
TypeError: one character string expected
>>> cstring = multiprocessing.Value(ctypes.c_char_p, "Hello, World!")
>>> cstring
<Synchronized wrapper for c_char_p(166841564)>
>>> cstring.value
'Hello, World!'

Для Python 3 используйте c_wchar_p вместо c_char_p

См. Также: Отправьте сообщение с исходным решением, которое мне было трудно найти.

Таким образом, диспетчер может использоваться для совместного использования строки в нескольких процессах в Python следующим образом:

>>> from multiprocessing import Process, Manager, Value
>>> from ctypes import c_char_p
>>> 
>>> def greet(string):
>>>     string.value = string.value + ", World!"
>>> 
>>> if __name__ == '__main__':
>>>     manager = Manager()
>>>     string = manager.Value(c_char_p, "Hello")
>>>     process = Process(target=greet, args=(string,))
>>>     process.start()
>>>     process.join()    
>>>     print string.value
'Hello, World!'
person Bengt    schedule 22.01.2014
comment
Мне было интересно, почему это работает (совместное использование указателя), и из источников я узнал, что managers.Value на самом деле вообще не использует аргумент typecode. Строка не преобразуется в c_char_p. multiprocessing.Value работает совсем иначе. - person Janne Karila; 23.01.2014
comment
Я пробовал s = multiprocessing.Value(c_char_p, "old string"), но s.value = "new string" часто терял указатель. Я также пробовал другое решение Array('c', fixed_length), более стабильное. - person John Lin; 02.11.2018
comment
Если вы попытаетесь избавиться от Manager, это не сработает, поскольку c_wchar_p - это всего лишь указатель на данные, поэтому, когда другой процесс обращается к ним, он переходит непосредственно к segmentation fault. Дополнительные объяснения можно найти здесь: stackoverflow.com/a/12343115/3300539. И да, как было сказано в предыдущем комментарии, Array('c', fixed_length) у меня тоже работает. - person VladVin; 07.06.2021

Просто поместите строку в dict:

d = manager.dict()
d['state'] = 'xyz'

Поскольку сами строки неизменяемы, совместное использование одной строки не так полезно.

person Janne Karila    schedule 22.01.2014
comment
manager.dict() медленнее, потому что он возвращает прокси, а прокси всегда копируют данные из одного потока в другой, а multiprocessing.Value() быстрее, потому что он возвращает фактическую область разделяемой памяти, к которой каждый процесс напрямую обращается. - person user; 31.08.2019