Что именно Thread.join () делает в python? Это неправильное использование Thread.join ()? - PullRequest
0 голосов
/ 26 июня 2018

Я совсем недавно начал изучать, как писать многопоточные программы на python, и для начала начал экспериментировать без с использованием очередей.

В приведенном ниже коде loadFunction - это просто пример целевой функции для потоков. предполагается , чтобы дождаться завершения всех потоков, представленных в аргументе wait (list), (и я пытаюсь добиться этого с помощью join ()). Затем , затем , начинают распечатывать указанный диапазон номеров. Это желаемое поведение.

В основной программе я создал два потока, которые не ожидают, пока другие потоки начнут считать. Затем я создал третий поток, который должен дождаться завершения первых двух потоков, прежде чем начнется его подсчет.

Однако этого не происходит. При тестировании я обнаружил, что три потока начинают выполняться одновременно, а третий поток не ждет, пока первые два не завершат выполнение, как я планировал.

Итак, мой вопрос здесь: какие знания мне не хватает в функции Thread.join () и какие изменения я могу внести в свой код для достижения желаемого результата?

Код:

""" Note: Python 3.3 onwards required since daemon was added as an initializable
    property from python 3.3 onwards."""

import threading

def loadFunction(name, start, end, wait=[]):
    """ wait should be a list of threads to wait for """
    map(lambda th: th.join(), wait)
    for number in range(start, end):
        print("%s : %d" % (name, number))

if __name__ == "__main__":
    t1 = threading.Thread(target=loadFunction, args=("Thread1", 1, 101), name="Thread1" ,daemon=True)
    t2 = threading.Thread(target=loadFunction, args=("Thread2", 101, 201), name="Thread2", daemon=True)
    t3 = threading.Thread(target=loadFunction, args=("Thread3", 1000, 1101, [t1, t2]), name="Thread3", daemon=True)

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

    # wait for all of the daemon processes to finish before we close the program
    t1.join()
    t2.join()
    t3.join()

    print("done!")

часть результата (за один проход):

Thread1 : 1
Thread1 : 2
Thread1 : 3
Thread1 : 4
Thread1 : 5
Thread1 : 6
Thread2 : 101
Thread2 : 102
Thread2 : 103
Thread2 : 104
Thread2 : 105
Thread2 : 106
Thread2 : 107
Thread2 : 108
Thread2 : 109
Thread1 : 7
Thread1 : 8
Thread1 : 9
Thread1 : 10
Thread1 : 11
Thread3 : 1000
Thread1 : 12
Thread1 : 13
Thread3 : 1001
Thread1 : 14
Thread3 : 1002
Thread1 : 15
Thread3 : 1003
Thread1 : 16
Thread2 : 110

Вот две вещи, которые приходили мне в голову, когда я писал этот код (как указано в официальной документации ):

присоединитесь (таймаут = None)

Дождитесь окончания потока. Это блокирует вызов поток, пока поток, чей метод join () вызывается, не завершится ...

Что касается моего примера кода, будет ли "вызывающий поток" быть тем потоком, который вызвал функцию loadFunction? У меня есть небольшое подозрение, что это не тот случай, и что сам процесс вызвал функцию, а не поток, следовательно, поток не будет тем, кто ожидает, но процесс ждет вместо. Если это так, как бы я это исправить? У меня такое ощущение, что очереди будут вовлечены ... , если это причина, в первую очередь.

и

Нить можно присоединить () к много раз.

- вот что заставляет меня дважды использовать join для одной и той же темы.

P.S. Я впервые изучаю многопоточность в Python, но это после изучения процессов разветвления в C, так что, возможно, я мог бы запутаться здесь из-за этого. Если эти два понятия не связаны, то я извиняюсь, у меня сложилось впечатление, что оба они похожи (хотя, очевидно, не то же самое, поскольку один разделяет процесс, а другой создает потоки внутри самого процесса).

Спасибо.

Ответы [ 2 ]

0 голосов
/ 26 июня 2018

будет ли "вызывающий поток" тем потоком, который называется функцией loadFunction?

Вызывающий поток - это тот поток, который называется join. поэтому t1.join() и t2.join() и t3.join() приводят к блокировке основного потока, а объединение внутри loadFunction приводит к блокированию t3, если map не обрабатывается лениво.

как бы это исправить?

Ваши объединения внутри loadFunction не выполняются, потому что map не выполняет никакого кода, пока вы не выполните итерацию по нему. Как предлагает MaxNoe, вы должны вместо этого использовать обычный цикл for.

def loadFunction(name, start, end, wait=[]):
    """ wait should be a list of threads to wait for """
    for t in wait:
        t.join()
    for number in range(start, end):
        print("%s : %d" % (name, number))
0 голосов
/ 26 июня 2018

, если вы хотите дождаться окончания двух первых потоков, прежде чем начинать третий, не вызывайте start() в третьем потоке перед join(), используя два других:

t1.start()
t2.start()

# wait for the threads above to finish before starting the third
t1.join()
t2.join()

t3.start() #now start it
t3.join()  # wait for it to finish
...