Как создать многопроцессорный массив строк в Python?

#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()