2013-10-02 19 views
22

Jestem nowy w wielowątkowość w python i próbuję nauczyć się wielowątkowości przy użyciu modułu wątków. Zrobiłem bardzo prosty program wielowątkowości i mam problem ze zrozumieniem metody threading.Thread.join.Korzystanie z threading.Thread.join()

Oto kod źródłowy programu zrobiłem

import threading 

val = 0 

def increment(): 
    global val 
    print "Inside increment" 
    for x in range(100): 
     val += 1 
    print "val is now {} ".format(val) 

thread1 = threading.Thread(target=increment, args=()) 
thread2 = threading.Thread(target=increment, args=()) 
thread1.start() 
#thread1.join() 
thread2.start() 
#thread2.join() 

Co to za różnica, czy używam

thread1.join() 
thread2.join() 

które pisali w powyższym kodzie? Uruchomiłem oba kody źródłowe (jeden z komentarzami i ten bez komentarzy), ale wynik jest taki sam.

+1

Prawdopodobny duplikat: http: // stackoverflow.com/questions/15085348/what-is-the-use-of-python-threading? answerertab = active # tab-top – Vivek

+0

Czy chcesz, aby twój kod działał, ponieważ jest poprawny lub przez przypadek? –

+1

@Vivek Mimo że tytuł zadanego pytania jest prawie taki sam, moje pytanie jest nieco prostsze i wymaga tylko podstawowej pracy funkcji join(). Ponieważ jestem nowy w wątkach, nie mogłem zrozumieć odpowiedzi udzielonej do wskazanego przez ciebie linka. Dlatego pomyślałem, że lepiej byłoby zadać nowe proste pytanie. –

Odpowiedz

61

Połączenie z numerem thread1.join() blokuje wątek, w którym nawiązujesz połączenie, do momentu zakończenia thread1. To jest jak wait_until_finished(thread1).

Na przykład:

import time 

def printer(): 
    for _ in range(3): 
     time.sleep(1.0) 
     print "hello" 

thread = Thread(target=printer) 
thread.start() 
thread.join() 
print "goodbye" 

drukuje

hello 
hello 
hello 
goodbye 

-bez zaproszenia .join(), goodbye przyjdzie, a potem 3 * hello.

Należy również pamiętać, że wątki w Pythonie nie zapewniają żadnej dodatkowej wydajności (pod względem mocy obliczeniowej procesora) z powodu czegoś zwanego Global Interpreter Lock, więc gdy są przydatne do odradzania potencjalnie blokowania (np. IO, sieć) i czasochłonne zadania (np. chrupanie numerów), aby główny wątek był wolny dla innych zadań, nie pozwalają one na wykorzystanie wielu rdzeni lub procesorów; w tym celu spójrz na multiprocessing, która używa podprocesów, ale udostępnia API równoważne z threading.

PLUG: ... i to jest również dla powyższego powodu, że, jeśli jesteś zainteresowany współbieżności, można również zajrzeć do drobnego biblioteki zwanej Gevent, które w istocie po prostu sprawia gwintem o wiele łatwiej używać, znacznie szybciej (gdy masz wiele równoczesnych działań) i mniej podatnych na błędy związane z współbieżnością, jednocześnie pozwalając ci zachować kodowanie w taki sam sposób, jak w przypadku "prawdziwych" wątków. Również Twisted, Eventlet, Tornado i wiele innych są równorzędne lub porównywalne. Ponadto, w każdym razie bym zdecydowanie wskazują przeczytaniu tych klasyków:

+11

+1. Dodatkowy przykład dla lepszego zrozumienia –

+1

"Zwróć też uwagę, że wątki w Pythonie nie zapewniają żadnej dodatkowej wydajności z powodu czegoś, co nazywa się Globalną Blokadą Interpretera ..." W wyniku tego powstaje zbyt szeroki uogólnienie i fałsz. Nawlekanie jest bardzo dobre dla zadań związanych z I/O i na pewno zapewnia tam korzyści wydajności. Istnieje wiele wątków omawiających ten punkt. – erewok

+0

@erewok: Musisz pominąć część, w której mówię * ", podczas gdy są one przydatne do odradzania się, potencjalnie blokując i pochłaniając czas" * i * ", nie pozwalają na wykorzystanie wielu rdzeni lub procesorów" * ... w dowolnym przypadku, zaktualizowałem swoją odpowiedź, aby było to bardziej jasne. –

1

Jako the relevant documentation stany, join sprawia, że ​​rozmówca czekać aż gwint kończy.

W twoim przypadku dane wyjściowe są takie same, ponieważ join nie zmienia zachowania programu - prawdopodobnie jest używane do całkowitego zamknięcia programu, tylko wtedy, gdy wszystkie wątki zostały zakończone.

3

Zmodyfikowałem kod, dzięki czemu zrozumiesz, jak dokładnie działa łączenie. więc uruchom ten kod z komentarzami i bez komentarzy i obserwuj dane wyjściowe dla obu.

val = 0 

def increment(msg,sleep_time): 
    global val 
    print "Inside increment" 
    for x in range(10): 
     val += 1 
     print "%s : %d\n" % (msg,val) 
     time.sleep(sleep_time) 

thread1 = threading.Thread(target=increment, args=("thread_01",0.5)) 
thread2 = threading.Thread(target=increment, args=("thread_02",1)) 
thread1.start() 
#thread1.join() 
thread2.start() 
#thread2.join() 
+0

dziękuję za odpowiedź, twój kod wyraźnie pokazuje różnicę pomiędzy użyciem join() i nieużywaniem tego –

+0

ostatnia linia powinna być '# thread2.join()' – WeizhongTu