Подтвердить что ты не робот

Передайте несколько параметров concurrent.futures.Executor.map?

concurrent.futures.Executor.map принимает переменное число итерируемых, из которой функция, заданная называется. Как мне это назвать, если у меня есть генератор, который производит кортежи, которые обычно распаковываются на месте?

Следующее не работает, потому что каждый из сгенерированных кортежей задан как отдельный аргумент для map:

args = ((a, b) for (a, b) in c)
for result in executor.map(f, *args):
    pass

Без генератора желаемые аргументы для отображения могут выглядеть так:

executor.map(
    f,
    (i[0] for i in args),
    (i[1] for i in args),
    ...,
    (i[N] for i in args),
)
4b9b3361

Ответ 1

Вам необходимо убрать * на map вызов:

args = ((a, b) for b in c)
for result in executor.map(f, args):
    pass

Это вызовет f, len(args) раз, где f должен принять один параметр.

Если вы хотите, чтобы f принял два параметра, вы можете использовать лямбда-вызов, например:

args = ((a, b) for b in c)
for result in executor.map(lambda p: f(*p), args):   # (*p) does the unpacking part
    pass

Ответ 2

Один аргумент, который повторяется, один аргумент в c

from itertools import repeat
for result in executor.map(f, repeat(a), c):
    pass

Нужно распаковать элементы c и распаковать c

from itertools import izip
for result in executor.map(f, *izip(*c)):
    pass

Необходимо распаковать элементы c, не распаковать c

  • Измените f, чтобы принять один аргумент и распаковать аргумент в функции.
  • Если каждый элемент в c имеет переменное число членов или вы вызываете f только несколько раз:

    executor.map(lambda args, f=f: f(*args), c)
    

    Определяет новую функцию, которая распаковывает каждый элемент из c и вызывает f. Использование аргумента по умолчанию для f в lambda делает f локальным внутри lambda и поэтому сокращает время поиска.

  • Если у вас есть фиксированное количество аргументов, и вам нужно много раз называть f:

    from collections import deque
    def itemtee(iterable, n=2):
        def gen(it = iter(iterable), items = deque(), next = next):
            popleft = items.popleft
            extend = items.extend
            while True:
                if not items:
                    extend(next(it))
                yield popleft()
        return [gen()] * n
    
    executor.map(f, *itemtee(c, n))
    

Где n - количество аргументов f. Это адаптировано из itertools.tee.

Ответ 3

Вы можете использовать curry для создания новой функции с помощью частичного метода в Python

from concurrent.futures import ThreadPoolExecutor
from functools import partial


def some_func(param1, param2):
    # some code

# currying some_func with 'a' argument is repeated
func = partial(some_func, a)
with ThreadPoolExecutor() as executor:
    executor.map(func, list_of_args):
    ...

Если вам нужно передать более одного параметра, вы можете передать их частичному методу

func = partial(some_func, a, b, c)