#python #multiprocessing
Вопрос:
Я пытаюсь создать многопроцессорный массив строк с помощью python 3 в ubuntu.
Как мне объявить массив? Я обнаружил, что, по-видимому, могу использовать типы символов (в частности, c_wchar_p для строки), поэтому я попробовал следующее:
from ctypes import c_wchar_p
from multiprocessing import Array
string_array = Array(c_wchar_p,range(10))
Ответ №1:
На самом деле, вы не можете легко использовать c_wchar_p
. Конечно, 3 инструкции, которые у вас есть, будут выполняться, но цель создания данных в общей памяти заключается в том, чтобы несколько процессов могли получить доступ к этим данным и обновить их, и проблема в том, что если вы сделаете следующее …
string_array[0] = 'abc'
… вы будете хранить в общей памяти адрес строки, относящейся к одному конкретному адресному пространству, и это будет недопустимый адрес, если на эту строку ссылается процесс в другом адресном пространстве. Документация для multiprocessing.sharedctypes
решения этой проблемы содержит следующее примечание:
Примечание. Хотя указатель можно хранить в общей памяти, помните, что он будет ссылаться на местоположение в адресном пространстве определенного процесса. Однако указатель, скорее всего, будет недействителен в контексте второго процесса, и попытка разыменования указателя от второго процесса может привести к сбою.
Вместо этого вы можете попробовать создать массив символов, размер которых является строкой максимального размера, которую вы ожидаете сохранить. Следующий код демонстрирует это:
from ctypes import c_wchar
from multiprocessing.sharedctypes import RawArray
from multiprocessing import Pool
def init_pool(the_arr):
global arr
arr = the_arr
def worker():
print(arr[0].value)
print(arr[1].value)
arr[2].value = 'It works!'
def main():
# create a list of 10 RawArrays, each one capable of holding 20-character strings
# The list itself is not meant to be modifiable, only the contained "strings"
arr = [RawArray(c_wchar, 20) for _ in range(10)]
arr[0].value = 'abc'
arr[1].value = 'defghijklmn'
# initialize process pool's processes' global variable arr
pool = Pool(2, initializer=init_pool, initargs=(arr,))
# worker function will execute in a different address space:
pool.apply(worker)
print(arr[2].value)
# Required for Windows:
if __name__ == '__main__':
main()
С принтами:
abc
defghijklmn
It works!
Если вам нужен изменяемый список (способный расти и уменьшаться), вам следует использовать управляемый список и забыть об общей памяти (это будет работать немного медленнее, если у вас много обращений, но более «естественно»).:
from multiprocessing import Pool, Manager
def init_pool(the_arr):
global arr
arr = the_arr
def worker():
print(arr[0])
print(arr[1])
arr.append('It works!')
def main():
arr = Manager().list(['abc', 'defghijklmn'])
# initialize process pool's processes' global variable arr
pool = Pool(2, initializer=init_pool, initargs=(arr,))
pool.apply(worker)
print(arr[2])
# Required for Windows:
if __name__ == '__main__':
main()