Являются ли общие данные только для чтения скопированы в разные процессы для многопроцессорности?
Кусок кода, который у меня есть, выглядит примерно так:
glbl_array = # a 3 Gb array
def my_func( args, def_param = glbl_array):
#do stuff on args and def_param
if __name__ == '__main__':
pool = Pool(processes=4)
pool.map(my_func, range(1000))
Есть ли способ удостовериться (или поощрять), чтобы разные процессы не получали копию glbl_array, но делили ее. Если нет способа остановить копию, я перейду с memmapped массивом, но мои шаблоны доступа не очень регулярны, поэтому я ожидаю, что массивы memmapped будут медленнее. Выше было похоже на первое, что нужно попробовать. Это на Linux. Я просто хотел получить совет от Stackoverflow и не хочу раздражать системный администратор. Как вы думаете, это поможет, если второй параметр является подлинным неизменяемым объектом, например glbl_array.tostring()
.
Ответы
Ответ 1
Вы можете использовать материал разделяемой памяти из multiprocessing
вместе с Numpy довольно легко:
import multiprocessing
import ctypes
import numpy as np
shared_array_base = multiprocessing.Array(ctypes.c_double, 10*10)
shared_array = np.ctypeslib.as_array(shared_array_base.get_obj())
shared_array = shared_array.reshape(10, 10)
#-- edited 2015-05-01: the assert check below checks the wrong thing
# with recent versions of Numpy/multiprocessing. That no copy is made
# is indicated by the fact that the program prints the output shown below.
## No copy was made
##assert shared_array.base.base is shared_array_base.get_obj()
# Parallel processing
def my_func(i, def_param=shared_array):
shared_array[i,:] = i
if __name__ == '__main__':
pool = multiprocessing.Pool(processes=4)
pool.map(my_func, range(10))
print shared_array
который печатает
[[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[ 2. 2. 2. 2. 2. 2. 2. 2. 2. 2.]
[ 3. 3. 3. 3. 3. 3. 3. 3. 3. 3.]
[ 4. 4. 4. 4. 4. 4. 4. 4. 4. 4.]
[ 5. 5. 5. 5. 5. 5. 5. 5. 5. 5.]
[ 6. 6. 6. 6. 6. 6. 6. 6. 6. 6.]
[ 7. 7. 7. 7. 7. 7. 7. 7. 7. 7.]
[ 8. 8. 8. 8. 8. 8. 8. 8. 8. 8.]
[ 9. 9. 9. 9. 9. 9. 9. 9. 9. 9.]]
Однако Linux имеет семантику copy-on-write на fork()
, поэтому даже без использования multiprocessing.Array
данные не будут скопированы, если они не записаны.
Ответ 2
Следующий код работает на Win7 и Mac (возможно, на Linux, но не протестирован).
import multiprocessing
import ctypes
import numpy as np
#-- edited 2015-05-01: the assert check below checks the wrong thing
# with recent versions of Numpy/multiprocessing. That no copy is made
# is indicated by the fact that the program prints the output shown below.
## No copy was made
##assert shared_array.base.base is shared_array_base.get_obj()
shared_array = None
def init(shared_array_base):
global shared_array
shared_array = np.ctypeslib.as_array(shared_array_base.get_obj())
shared_array = shared_array.reshape(10, 10)
# Parallel processing
def my_func(i):
shared_array[i, :] = i
if __name__ == '__main__':
shared_array_base = multiprocessing.Array(ctypes.c_double, 10*10)
pool = multiprocessing.Pool(processes=4, initializer=init, initargs=(shared_array_base,))
pool.map(my_func, range(10))
shared_array = np.ctypeslib.as_array(shared_array_base.get_obj())
shared_array = shared_array.reshape(10, 10)
print shared_array
Ответ 3
Для тех, кто застрял в Windows, который не поддерживает fork()
(если не используется CygWin), ответ pv не работает. Глобалы не доступны для дочерних процессов.
Вместо этого вы должны передать разделяемую память во время инициализатора Pool
/Process
как таковой:
#! /usr/bin/python
import time
from multiprocessing import Process, Queue, Array
def f(q,a):
m = q.get()
print m
print a[0], a[1], a[2]
m = q.get()
print m
print a[0], a[1], a[2]
if __name__ == '__main__':
a = Array('B', (1, 2, 3), lock=False)
q = Queue()
p = Process(target=f, args=(q,a))
p.start()
q.put([1, 2, 3])
time.sleep(1)
a[0:3] = (4, 5, 6)
q.put([4, 5, 6])
p.join()
(это не numpy и это не хороший код, но он иллюстрирует точку; -)
Ответ 4
Если вы ищете вариант, который эффективно работает в Windows и хорошо работает для нерегулярных шаблонов доступа, ветвления и других сценариев, где вам может потребоваться проанализировать разные матрицы на основе комбинации матрицы с общей памятью и процесса, локальные данные, набор инструментов mathDict в пакете ParallelRegression был разработан для обработки этой точной ситуации.