Использование threading.Thread.join()
Я новичок в многопоточности в python и пытаюсь изучить многопоточность с использованием модуля потоковой передачи. Я сделал очень простую программу многопоточности, и мне трудно понять метод threading.Thread.join
.
Вот исходный код программы, которую я создал
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()
Какая разница, если я использую
thread1.join()
thread2.join()
который я прокомментировал в приведенном выше коде? Я запускал оба исходных кода (один с комментариями и один без комментариев), но вывод тот же.
Ответы
Ответ 1
Вызов thread1.join()
блокирует поток, в котором вы выполняете вызов, до тех пор, пока thread1
не будет завершен. Это нравится wait_until_finished(thread1)
.
Например:
import time
def printer():
for _ in range(3):
time.sleep(1.0)
print "hello"
thread = Thread(target=printer)
thread.start()
thread.join()
print "goodbye"
печатает
hello
hello
hello
goodbye
- без вызова .join()
, сначала будет goodbye
, а затем 3 * hello
.
Также обратите внимание, что потоки в Python не обеспечивают дополнительной производительности (с точки зрения мощности процессора) из-за вещи, называемой Global Interpreter Lock, так что, хотя они полезны для отсрочки потенциальной блокировки (например, IO, сети) и трудоемких задач (например, хруст числа), чтобы поддерживать основной поток для других задач, они не позволяют использовать несколько ядер или процессоров; для этого просмотрите multiprocessing
, который использует подпроцессы, но предоставляет API, эквивалентный API threading
.
PLUG:... и по вышеуказанной причине, если вы заинтересованы в concurrency, вам также может понадобиться посмотреть в тонкую библиотеку Gevent, которая по существу просто делает потоки намного проще в использовании, гораздо быстрее (когда у вас много одновременных действий) и менее подвержен ошибкам concurrency, а также позволяет кодировать то же самое, что и с "настоящими" потоками. Также Twisted, Eventlet, Tornado и многие другие эквивалентны или сопоставимы. Кроме того, в любом случае я настоятельно рекомендую прочитать эти классики:
Ответ 2
Я изменил код, чтобы вы поняли, как работает соединение.
поэтому запустите этот код с комментариями и без комментариев и посмотрите вывод для обоих.
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()
Ответ 3
Как соответствующая документация, join
заставляет вызывающего абонента ждать окончания потока.
В вашем случае результат тот же, поскольку join
не изменяет поведение программы - он, вероятно, используется для выхода из программы чисто, только когда все потоки завершены.