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 шт):

Автор решения: eri

Потому что функцию исполняете не в экзекуторе. Используйте лямбду или 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

→ Ссылка