web-dev-qa-db-ja.com

複数のパラメーターをconcurrent.futures.Executor.mapに渡しますか?

concurrent.futures.Executor.map は、指定された関数の呼び出し元となる可変数のイテラブルを取ります。 通常は展開されているタプルを生成するジェネレーターがある場合、どのように呼び出す必要がありますか?

生成されたタプルのそれぞれがマップする異なる引数として指定されているため、以下は機能しません。

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

ジェネレーターがない場合、mapに必要な引数は次のようになります。

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

map呼び出しで_*_を削除する必要があります:

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

これはflen(args)を呼び出します。ここで、fは1つのパラメーターを受け入れる必要があります。

fが2つのパラメーターを受け入れるようにするには、次のようなラムダ呼び出しを使用できます。

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

繰り返される1つの引数、cの1つの引数

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を解凍できません

  1. fを変更して単一の引数を取り、関数の引数をアンパックします。
  2. cの各アイテムに可変数のメンバーがある場合、またはfを数回だけ呼び出している場合:

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

    cから各項目をアンパックし、fを呼び出す新しい関数を定義します。 flambdaのデフォルト引数を使用すると、flambda内でローカルになり、ルックアップ時間が短縮されます。

  3. 固定数の引数があり、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))
    

ここで、nfへの引数の数です。これは itertools.tee

38
agf

Pythonで partial メソッドを使用して、カリー化を使用して新しい関数を作成できます

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

同じパラメータを複数渡す必要がある場合は、それらを partial メソッドに渡すことができます

func = partial(some_func, a, b, c)
9
Vlad Bezden

したがって、takes argumentsの関数があり、3つの引数すべてがdynamicであり、呼び出しのたびに変化し続けると仮定します。例えば:

def multiply(a,b,c):
    print(a * b * c)

スレッドを使用してこれを複数回呼び出すには、最初にタプルのリストを作成します。ここで、各タプルはa、b、cのバージョンです。

arguments = [(1,2,3), (4,5,6), (7,8,9), ....]

私たちはそれを知っていますconcurrent.futuresmap関数は、実行される関数のバージョンごとに、最初の引数をターゲット関数として受け入れ、2番目の引数を引数のリストとして受け入れます。したがって、次のような呼び出しを行う可能性があります。

for _ in executor.map(multiply, arguments) # Error

しかし、これはあなたにerror関数が期待する3 arguments but got only 1。この問題を解決するために、ヘルパー関数を作成します。

def helper(numbers):
    multiply(numbers[0], numbers[1], numbers[2])

これで、executorを使用してこの関数を次のように呼び出すことができます。

with ThreadPoolExecutor() as executor:
     for _ in executor.map(helper, arguments):
         pass

これで望ましい結果が得られるはずです。

1
Baqir Khan

ProcessPoolExecutor.map() の場合:

Map(func、* iterables)に似ていますが、次の点が異なります。

反復可能オブジェクトは、遅延ではなく即座に収集されます。

funcは非同期に実行され、funcへの複数の呼び出しが同時に行われる場合があります。

python 3の下で次のスニペットを実行してみてください。そうすれば、非常に明確になります。

from concurrent.futures import ProcessPoolExecutor

def f(a, b):
    print(a+b)

with ProcessPoolExecutor() as pool:
    pool.map(f, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9), (0, 1, 2))

# 0, 2, 4

array = [(i, i) for i in range(3)]
with ProcessPoolExecutor() as pool:
    pool.map(f, *Zip(*array))

# 0, 2, 4
0
Tengerye

ここでは非常に多くの答えを見てきましたが、ラムダ式を使用するほど簡単なものはありません。

foo(x、y):渡す

上記のメソッドを同じ値、つまりxValとyValで10回呼び出したいですか? executorとしてconcurrent.futures.ThreadPoolExecutor()を使用:

for _ in executor.map( lambda _: foo(xVal, yVal), range(0, 10)):
    pass
0
H L