2011-11-23 26 views
15

Używam Pythona 2.7, mam jakiś kod, który wygląda tak:wykonywania zadań równolegle pytona

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

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

dependent3() 

Jedyne zależności tutaj są następujące: dependent1 musi czekać na tasks1-3, dependent2 potrzeb czekać na zadania 4-6, a zależne3 musi czekać na zależności1-2 ... Poniższe byłoby w porządku: uruchomienie wszystkich sześciu zadań najpierw równolegle, następnie pierwszych dwóch zależnych równolegle .. następnie ostateczna zależna

Wolę równoległe wykonywanie jak największej liczby zadań, szukałem niektórych modułów, ale miałem nadzieję uniknąć bibliotek zewnętrznych i nie wiem, w jaki sposób Technika ue-Thread może rozwiązać mój problem (może ktoś może polecić dobry zasób?)

+0

Zalecam używanie metod standardowej * Queue.task_done * i * Queue.join * do synchronizowania wątków. U dołu strony w dokumentach Kolejki znajdziesz przykład oczekiwania na zakończenie innych zadań: http://docs.python.org/library/queue.html#Queue.Queue.join –

+0

Jeśli Twój kod jest bardziej złożony, warto zajrzeć do bibliotek zewnętrznych, ponieważ istnieją już rzeczy, które radzą sobie z równoległymi uruchomieniami zadań, jednocześnie upewniając się, że zależności działają w kolejności. –

+0

Z powodu GIL wątki będą się uruchamiać tylko jeden po drugim w standardowym pythonie. Przyszłe wersje Pypy używające STM mogą jednak to obejść. –

Odpowiedz

24

Klasa wbudowana threading.Thread oferuje wszystko, czego potrzebujesz: start, aby rozpocząć nowy wątek i join, aby poczekać na koniec wątku.

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

Alternatywnie do połączenia można użyć Queue.join, aby poczekać na zakończenie wątków.

+1

To jest świetne! ale moje funkcje zadania zwracają wartości, które używam w funkcjach dep, w jaki sposób uzyskać zwrócone wartości z t1, t2, t3 itd ..? –

+2

Pierwsze trafienie w SO daje mi http://stackoverflow.com/questions/1886090/return-value-from-thread – gecco

+0

Co jeśli chcę przekazać kilka argumentów do funkcji? – Lavish

2

Spójrz na Gevent.

Przykład użycia:

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) 

Hope, to jest to, czego szukaliśmy.

+2

Naprawdę? OP poprosił o rozwiązanie wielowątkowe za pomocą techniki kolejki/wątku i chciał uniknąć bibliotek zewnętrznych. Ale wskazujesz mu gniazdo zewnętrznych zależności i ignorujesz podstawowe rozwiązania dostarczane przez bibliotekę standardową. –

+2

Punkt dobrze zrobiony. – meson10