ProcessPoolExecutor не ускоряет время работы скрипта. В чем проблема и как исправить?
Использую ProcessPoolExecutor для того, чтобы распаралелить процессы и ускорить выполнения скрипта. Но, при применении ProcessPoolExecutor, ускорения не происходит. Вот код
Функция для выполнения:
def polygon_n(i):
print('Area %s'%(i))
pol = arr_test[i][0]
poly = Polygon(pol)
global z
z=z+1
x_max, x_min = max_min_coord(pol, 0)
y_max, y_min = max_min_coord(pol, 1)
gen_long(Island, z, 'long', x_min, x_max)
gen_lat(Island, z, 'lat', y_min, y_max)
gen100(Island, z, 'long', x_min, x_max)
gen100(Island, z, 'lat', y_min, y_max)
gen_double(Island, z, 'long', x_min, x_max)
gen_double(Island, z, 'lat', y_min, y_max)
with open('Files2/%s_%s_%s_%s_%s_%s.txt'%(Island, z, 'long', x_min, x_max, 'double'), 'r') as long:
for i in long:
i_1, i_2 = i.split()
with open('Files2/%s_%s_%s_%s_%s_%s.txt'%(Island, z, 'lat', y_min, y_max, 'double'), 'r') as short:
for k in short:
k_1, k_2 = k.split()
string = ''
coord = [[float(i_1),float(k_1)],[float(i_2),float(k_1)],[float(i_2),float(k_2)],
[float(i_1),float(k_2)], [float(i_1),float(k_1)]]
pol_pixel = Polygon(coord)
if poly.intersects(pol_pixel):
global count
count+=1
row = ['%s'%count, coord]
cursor.insertRow(row)
string += '{"area": "' + str('%s'%count)+'", "geometry": "{\\"type\\": \\"Polygon\\", \\"coordinates\\": [[['+str(i_1) + ',' + str(k_1)+ ']'+',' + '[' + str(i_2)+','+str(k_1) + ']'+',' + '['+str(i_2)+ ',' + str(k_2) +'],' + '['+str(i_1)+ ',' + str(k_2) +'],' + '[' + str(i_1)+ ',' + str(k_1) +']]]}"}\n'
fin.write(string)
Распаралеливание процессов:
executor = ProcessPoolExecutor(max_workers=8)
start = time.time()
with arcpy.da.InsertCursor(feature_class, ['ID','SHAPE@']) as cursor, open('JSON/%s.json'%Island, 'w') as fin:
for i in range(0, len(arr_test)):
executor.submit(polygon_n(i))
print(z)
del cursor
end = time.time()
Код выполняется то же время, что и без использования ProcessPoolExecutor. Где я ошибся и как исправить ошибку? Спасибо
P. S. Этого кода должно быть достаточно. Если надо - наведу весь код скрипта.
Ответы (1 шт):
Потому что функцию исполняете не в экзекуторе. Используйте лямбду или functools.partials там где не принимаются аргументы, в случае submit аргументы идут сразу за функцией.
executor.submit(polygon_n, i)
Также можно убрать for в вашем случае
executor.map(polygon_n, range(0, len(arr_test)))
По переделке тут ешё много вопросов
arr_test - лучше передавать не индекс, а само значение
def polygon_n(test)
pol = test[0]
....
executor.map(polygon_n, arr_test)
глобальная z не прокатит в процессах - нужно multiprocessing.Value
from multiprocessing import Value
z=Value('i', 0)
def polygon_n(z, test):
...
z.value+=1
...
executor.map(functools.partial(polygon_n, z), arr_test))
Теперь с fin - тоже глобальная штука, но при этом файл: писать его из разных процессов без блокировок - плохая идея. Тут надо делать очередь или блокировки
manager = multiprocessing.Manager()
# z тоже лучше через менеджера гонять
z = manager.Value('i', 0)
q = manager.Queue()
def polygon_n(z,q, test):
...
#fin.write(string)
q.put(string)
...
executor.map(functools.partial(polygon_n, z, q), arr_test))
... а потом эту очередь вычитываем и пишем в файл
def write_fin(q)
with open(fn, 'w') as f:
while 1:
m = q.get()
if m is None:
break
f.write(m)
f.flush()
executor.submit(write_fin, q)
executor.map(...
q.put(None) # индикатор конца записи
Вот тут ещё курсор... Курсор нужно делать новый для каджого процесса если это курсор от базы данных
В пул процессов передаешь функцию initializer
... initializer=make_cursor, initargs=('db=127.0.0.1 user=user') ...
С count та же фигня что и с z