Pasa múltiples parámetros a concurrent.futures.Executor.map?

El concurrent.futures.Executor.map toma un número variable de iterables desde los cuales se llama la función dada. ¿Cómo debería llamarlo si tengo un generador que produce tuplas que normalmente se desempaquetan?

Lo siguiente no funciona porque cada una de las tuplas generadas se presenta como un argumento diferente para mapear:

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

Sin el generador, los argumentos deseados para mapear podrían verse así:

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

Debe eliminar el * en la llamada de map :

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

Esto llamará f , len(args) veces, donde f debería aceptar un parámetro.

Si desea que f acepte dos parámetros, puede usar una llamada lambda como:

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

Un argumento que se repite, un argumento en c

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

Necesidad de desempacar artículos de c , y puede desempaquetar c

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

Necesito desempacar artículos de c , no puedo desempacar c

  1. Cambie f para tomar un solo argumento y descomprimir el argumento en la función.
  2. Si cada elemento en c tiene un número variable de miembros, o está llamando f solo unas pocas veces:

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

    Define una nueva función que desempaqueta cada elemento de c llama a f . El uso de un argumento predeterminado para f en la lambda hace que f sea ​​local dentro de la lambda y así reduce el tiempo de búsqueda.

  3. Si tiene un número fijo de argumentos y necesita llamar a f muchas veces:

     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)) 

Donde n es el número de argumentos para f . Esto es una adaptación de itertools.tee .

Puedes usar el curry para crear una nueva función a través del método parcial en 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): ... 

Si necesita pasar más de uno los mismos parámetros, puede pasarlos a un método parcial

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