Передайте несколько параметров 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),
)
Ответы
Ответ 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)