web-dev-qa-db-ja.com

pythonでタスクを並列実行する

python 2.7を使用しています。次のようなコードがあります。

task1()
task2()
task3()
dependent1()

task4()
task5()
task6()
dependent2()

dependent3()

ここでの唯一の依存関係は次のとおりです。dependent1はtasks1-3を待つ必要があり、dependent2はtask 4-6を待つ必要があり、dependent3はdependents1-2を待つ必要があります...次は大丈夫です:最初に6つのタスク全体を実行します並列で、最初の2つの従属が並列で..最後の従属

できるだけ多くのタスクを並行して実行したいので、いくつかのモジュールをグーグル検索しましたが、外部ライブラリを回避したいと思っていました。キュースレッドテクニックで問題を解決できるかどうかわかりません(たぶん誰かが良いリソースを勧めることができます) ?)

27
Mohamed Khamis

組み込みの threading.Thread クラスは必要なすべてを提供します: start は新しいスレッドを開始し、 join はスレッドの終了を待ちます。

import threading

def task1():
    pass
def task2():
    pass
def task3():
    pass
def task4():
    pass
def task5():
    pass
def task6():
    pass

def dep1():
    t1 = threading.Thread(target=task1)
    t2 = threading.Thread(target=task2)
    t3 = threading.Thread(target=task3)

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

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

def  dep2():
    t4 = threading.Thread(target=task4)
    t5 = threading.Thread(target=task5)

    t4.start()
    t5.start()

    t4.join()
    t5.join()

def dep3():
    d1 = threading.Thread(target=dep1)
    d2 = threading.Thread(target=dep2)

    d1.start()
    d2.start()

    d1.join()
    d2.join()

d3 = threading.Thread(target=dep3)
d3.start()
d3.join()

別の方法として参加するには、スレッドの終了を待機するために Queue.join を使用できます。

33
gecco

外部ライブラリを試してみたいと思っている場合は、タスクとその依存関係を Ray でエレガントに表現できます。これは単一のマシンでうまく機能します。ここでの利点は、並列処理と依存関係がpython multiprocessingを使用するよりもレイで表現するほうが簡単で、GIL(グローバルインタープリターロック)の問題がないことです。これにより、マルチスレッドが効率的に機能しなくなることがよくあります。

ソリューションは次のようになります。

import ray

ray.init()

@ray.remote
def task1():
    pass

@ray.remote
def task2():
    pass

@ray.remote
def task3():
    pass

@ray.remote
def dependent1(x1, x2, x3):
    pass

@ray.remote
def task4():
    pass

@ray.remote
def task5():
    pass

@ray.remote
def task6():
    pass

@ray.remote
def dependent2(x1, x2, x3):
    pass

@ray.remote
def dependent3(x, y):
    pass

id1 = task1.remote()
id2 = task2.remote()
id3 = task3.remote()

dependent_id1 = dependent1.remote(id1, id2, id3)

id4 = task4.remote()
id5 = task5.remote()
id6 = task6.remote()

dependent_id2 = dependent2.remote(id4, id5, id6)

dependent_id3 = dependent3.remote(dependent_id1, dependent_id2)

ray.get(dependent_id3) # This is optional, you can get the results if the tasks return an object

タスク内の引数を使用して結果を返すことにより、タスク間で実際のpython=オブジェクトを渡すこともできます(たとえば、上記の「パス」の代わりに「戻り値」と言って))。

「pip install ray」を使用すると、上記のコードは単一のマシンでそのまま使用できます。また、クラウドまたは独自のカスタムクラスターのいずれかで、クラスター上のアプリケーションを並列化することも簡単です。 https:// ray.readthedocs.io/en/latest/autoscaling.html および https://ray.readthedocs.io/en/latest/using-ray-on-a-cluster.html ) 。これは、ワークロードが後で増加する場合に役立ちます。

免責事項:私はレイの開発者の一人です。

2
Philipp Moritz

Gevent を見てください。

使用例:

import gevent
from gevent import socket

def destination(jobs):
    gevent.joinall(jobs, timeout=2)
    print [job.value for job in jobs]

def task1():
    return gevent.spawn(socket.gethostbyname, 'www.google.com')

def task2():
    return gevent.spawn(socket.gethostbyname, 'www.example.com')

def task3():
    return gevent.spawn(socket.gethostbyname, 'www.python.org')

jobs = []
jobs.append(task1())
jobs.append(task2())
jobs.append(task3())
destination(jobs)

これがあなたが探していたものです。

1
meson10