4

私がやりたいのは、複数のスレッドで関数を呼び出して、その結果を取得できるようにすることです。

私は次のコードを持っています:

(これは例です。実際のコードは単にstrをintに変換するだけではありません)

from threading import Thread
import time
import Queue

#an example - actual code connects to a server
def str_to_int(arg, queue):
    result = 0
    result = int(arg)
    #sleep to check that they happen at once.
    time.sleep(10)
    queue.put(result)

def combine():
    q1 = Queue.Queue()
    q2 = Queue.Queue()
    q3 = Queue.Queue()

    t1 = Thread(target = str_to_int, args=("111", q1))
    t2 = Thread(target = str_to_int, args=("222", q2))
    t3 = Thread(target = str_to_int, args=("333", q3))

    t1.start()
    t2.start()
    t3.start()

    t1.join()
    t2.join()
    t3.join()

    return (q1.get(),q2.get(),q3.get())

print combine()

このコードは機能します。そして私は期待される結果を得る:

>>> 
(111, 222, 333)

ただし、これを行うためのより良い方法が必要です。私は3つよりも多くのスレッドを使用する予定ですが、3つしか使用していなかったとしても、非常に醜いようです。

編集:どの結果がどのスレッドから来たのかを知る必要があります(つまり、関数に与えたパラメーター/引数から)

4

2 に答える 2

7

ここにいくつかのアドバイスがあります:

  1. Queueはスレッドセーフであるため、1つのキューを使用して結果を渡します。
  2. サイクル内のすべてのスレッドを作成し、キューを使用して結果を渡すことができます。スレッドごとに明示的な変数を用意する必要はありません。

したがって、コードは次のようになります。

def str_to_int(arg, queue):
    result = int(arg)
    queue.put({arg: result})

def combine():
    arguments = ('111', '222', '333')
    q = Queue.Queue()
    threads = []

    for argument in arguments:
        t = Thread(target=str_to_int, args=(argument, q))
        t.start()
        threads.append(t)

    for t in threads:
        t.join()

    return [q.get() for _ in xrange(len(arguments))]
于 2012-08-16T11:31:39.120 に答える
0

どの結果がどのスレッドからのものであるかを知る必要があります(つまり、関数に与えたパラメーター/引数から)

このような関数を使用して、どの結果がどのタスクから発生したかを追跡します。

from threading import Thread
import typing

def run_together(tasks: typing.Dict[typing.Hashable, tuple],
                 except_errors: tuple = None) -> dict:
    """
    :param tasks: a dict of task keys matched to a tuple of callable and its arguments
    <pre>tasks = {'task1': (add, 1, 2), 'task2': (add, 3, 4)}</pre>

    :param except_errors: a tuple of errors that should be catched. Defaults to all errors 
    :return: a dictionary of results with the same keys as `tasks` parameter
    <pre>results = {'task1': 3, 'task2': 7}</pre>
    """
    # catch all exceptions by default
    if not except_errors:
        except_errors = (Exception,)
    threads = []
    results = dict()

    def save_results(f, key):
        def wrapped(*args, **kwargs):
            try:
                result = f(*args, **kwargs)
            except except_errors as e:
                result = e
            results[key] = result

        return wrapped

    for key, (func, *args) in tasks.items():
        thread = Thread(
            target=save_results(func, key),
            args=args
        )
        thread.start()
        threads.append(thread)

    for t in threads:
        t.join()

    return results

tasksパラメータは、キーのディクショナリとその引数を持つ呼び出し可能のタプルです。必要に応じて、デコレータを変更saveしてを返すことができlistます。

だからあなたはすることができます:

def add(first, second):
    return first + second

tasks = {f'result:{n}': (add, n, 1) for n in range(4)}
results = run_together(tasks)
print(results)

これは次のようになります。

{'result:0': 1, 'result:1': 2, 'result:2': 3, 'result:3': 4}
于 2019-03-03T21:26:35.853 に答える