Как я могу использовать python многопроцессорную работу с генераторами? - PullRequest
0 голосов
/ 22 марта 2020

Я хотел бы использовать многопроцессорность в python с функциями генератора

Допустим, у меня есть огромный список списков big_list, и я хотел бы использовать многопроцессорность для вычисления значений. Если я использую «традиционные» функции, которые возвращают значения, это просто:

import concurrent

def compute_function(list_of_lists):
    return_values = []   ## empty list
    for list in list_of_lists:
        new_value = compute_something(list)    ## compute something; just an example
        return_values.append(new_value)  ## append to list
    return return_values

with concurrent.futures.ProcessPoolExecutor(max_workers=N) as executor:
        new_list = list(executor.map(compute_function, big_list))

Однако использование списков таким способом требует слишком много памяти. Поэтому я хотел бы использовать вместо этого функции генератора:

import concurrent

def generator_function(list_of_lists):
    for list in list_of_lists:
        new_value = compute_something(list)    ## compute something; just an example
        yield new_value

with concurrent.futures.ProcessPoolExecutor(max_workers=N) as executor:
        new_list = list(executor.map(generator_function, big_list))

Моя проблема в том, что вы не можете работать с генераторами. Есть некоторые обходные пути для этой проблемы для других структур данных, но не для генераторов, я думаю.

Как я мог выполнить sh это?

Ответы [ 2 ]

0 голосов
/ 22 марта 2020

Вы можете выполнить перечисление на один уровень глубже в big_list, используя itertools.chain.from_iterable для итерации подсписков.

import concurrent
import itertools

def compute_function(item):
    return compute_something(item)

with concurrent.futures.ProcessPoolExecutor(max_workers=N) as executor:
    for result in executor.map(compute_function,
            itertools.chain.from_iterable(big_list)):
        print(result)
0 голосов
/ 22 марта 2020
Генератор

- это просто модный l oop, который сохраняет состояние, он похож на logi c итератора, он предоставляет вам next, hasNext и аналогичные API, так что ваш l oop будет попросите этот итератор для следующего элемента (если он имеет следующий элемент)

имплантация генератора полностью зависит от разработчика, его можно реализовать с помощью

  • , загрузив все данные в память и перебирайте их с помощью следующего, таким образом, не достигая эффективного использования памяти, например, for i in [1,2,3,4]
  • чтение строка за строкой некоторого файла, например, for line in file
  • , если известна функция генерации, генерировать следующий элемент на основе последнего сгенерированного элемента, например, как в range(100)
  • и многом другом ...

у всех есть общее требование, где генератор должен хранить его текущее состояние, поэтому он будет знать, что yield в следующем состоянии, что делает его очень большим с состоянием , что, в свою очередь, делает его очень плохим выбором для многопроцессорной обработки ...

Вы можете подойти к этой проблеме с картой- уменьшить аналогичные логики c и разбить весь список на маленькие подсписки, передать их рабочим и объединить весь их вывод в окончательный результат

...