Как заставить 3 нити печатать последовательно - PullRequest
0 голосов
/ 08 февраля 2019

Мне нужно сделать 3 нити для печати цветов семафора: красного, желтого и зеленого в этом порядке, и после этого каждый шаг должен спать в течение N секунд в случайном порядке.Каждый цвет должен быть напечатан для одной нити, и весь этот процесс должен повторяться N раз.

Я пытался переместить lock.acquire () и lock.release () из цикла for, но он не работает = (

from termcolor import colored
import threading
import time
from random import randrange


def threadRed(n, lock, tempo):
    for i in range(n):
        lock.acquire()
        print(colored("red", 'grey', 'on_red', attrs=['dark', 'bold']))
        print(colored("I'm going to sleep for %d seconds," % tempo, 'red'))
        time.sleep(tempo)
        lock.release()


def threadYellow(n, lock, tempo):
    for i in range(n):
        lock.acquire()
        print(colored("yellow", 'grey', 'on_yellow', attrs=['dark', 'bold']))
        print(colored("I'm going to sleep for %d seconds," % tempo, 'yellow'))
        time.sleep(tempo)
        lock.release()


def threadGreen(n, lock, tempo):
    for i in range(n):
        lock.acquire()
        print(colored("green", 'grey', 'on_green', attrs=['dark', 'bold']))
        print(colored("I'm going to sleep for %d seconds," % tempo, 'green'))
        time.sleep(tempo)
        lock.release()


lock = threading.Lock()
repeticoes = 5
tempo = randrange(1, 11)
t_red = threading.Thread(target=threadRed, args=(repeticoes, lock, tempo))
tempo = randrange(1, 11)
t_yellow = threading.Thread(target=threadYellow, args=(repeticoes, lock, tempo))
tempo = randrange(1, 11)
t_green = threading.Thread(target=threadGreen, args=(repeticoes, lock, tempo))

t_red.start()
t_yellow.start()
t_green.start()
t_red.join()
t_yellow.join()
t_green.join()

Вкратце мой код печатает, что:

actual result

но мне нужно, чтобы это было отображаемым результатом:

expected result

Ответы [ 4 ]

0 голосов
/ 15 февраля 2019

Это еще одна версия того же кода, но с использованием чистого семафора вместо событий

from termcolor import colored
import threading
import time
from random import randrange


semaforo1 = threading.Semaphore()
semaforo2 = threading.Semaphore()
semaforo3 = threading.Semaphore()



def printThread(color):
    duration = randrange(1, 11)
    print(colored(color, 'grey', 'on_'+color, attrs=['dark', 'bold']))
    print(colored("I'm going sleep for %d seconds!," % duration, color))
    time.sleep(duration)

def threadRed(n):
    semaforo2.acquire()
    semaforo3.acquire()
    for i in range(n):
        semaforo1.acquire()
        printThread("red")
        #semaforo1.release()
        semaforo2.release()


def threadYellow(n):
    for i in range(n):
        semaforo2.acquire()
        printThread("yellow")
        semaforo3.release()



def threadGreen(n):
    for i in range(n):
        semaforo3.acquire()
        printThread("green")
        semaforo1.release()




loop_count = 5

t_red = threading.Thread(target=threadRed, args=(loop_count,))

t_yellow = threading.Thread(target=threadYellow, args=(loop_count,))

t_green = threading.Thread(target=threadGreen, args=(loop_count,))


t_red.start()
t_yellow.start()
t_green.start()
t_red.join()
t_yellow.join()
t_green.join()
0 голосов
/ 08 февраля 2019

Не пытайтесь использовать threading.Lock().Объект lock предназначен только для взаимного исключения (т. Е. Для предотвращения одновременного доступа двух и более потоков к одним и тем же данным.) Он не предназначен для связи между потоками.

IMO, лучший способ сделать это - использовать три Semaphore экземпляра.У Python есть класс asyncio.Semaphore, но я немного озадачен словами "не безопасен для потоков" в его документации.Я никогда не использовал этот класс, но он выглядит как семафоры из других языковых библиотек, которые предназначены для передачи сигналов между потоками.

Семафор похож на очередь блокировки, которая содержит ноль или более * разрешения 1016 *.Разрешения являются абстрактными;они на самом деле не существуют.Семафор просто ведет подсчет того, сколько из них он должен «содержать» в любой данный момент времени.

Вызывающий абонент может попытаться acquire() получить разрешение, которое уменьшит счет и сразу же вернет его, если счет был больше нуля, или будет ожидать, пока какой-либо другой поток release() sa не разрешит иначе.

Итак, вот как вы бы это использовали:

Создайте три пустых семафора (count == 0), по одному для каждого из ваших потоков, и дайте каждому потоку ссылку на свой собственный семафор, а также,на семафор следующего потока.Затем каждый поток должен выполнить цикл:

for i in range(n):
    self.my_semaphore.acquire()        # thread waits here until signalled.
    print( ... )
    self.next_guys_semaphore.release() # signals the next guy.

После того, как ваш основной поток создал три семафора и три рабочих потока, ничего не произойдет, потому что все три рабочих будут ждать в acquire().Итак, последнее, что нужно сделать основному потоку, это red_worker_semaphore.release(), а затем они должны начать работать, один за другим, в правильном порядке.

0 голосов
/ 09 февраля 2019

Я сделал это!

Спасибо всем за советы!но я переделываю весь свой код, используя o threading.Lock () и threading.Event (), и все в порядке!

from termcolor import colored
import threading
import time
from random import randrange


lock = threading.Lock()
event = threading.Event()


def printThread(color):
    duration = randrange(1, 11)
    print(colored(color, 'grey', 'on_'+color, attrs=['dark', 'bold']))
    print(colored("I'm going sleep for %d seconds!," % duration, color))
    time.sleep(duration)

def threadRed(n):
    for i in range(n):
        lock.acquire()
        printThread("red")
        lock.release()
        event.set()
        event.wait()
        event.clear()


def threadYellow(n):
    for i in range(n):
        lock.acquire()
        printThread("yellow")
        lock.release()
        event.set()
        event.wait()
        event.clear()


def threadGreen(n):
    for i in range(n):
        lock.acquire()
        printThread("green")
        lock.release()
        event.set()
        event.wait()
        event.clear()



loop_count = 5

t_red = threading.Thread(target=threadRed, args=(loop_count,))

t_yellow = threading.Thread(target=threadYellow, args=(loop_count,))

t_green = threading.Thread(target=threadGreen, args=(loop_count,))


t_red.start()
t_yellow.start()
t_green.start()
t_red.join()
t_yellow.join()
t_green.join()
0 голосов
/ 08 февраля 2019

Хорошо, вы хотите, чтобы вывод убил всю точку multi-threading.

Почему?

У потока есть начало,последовательность выполнения и вывод.У него есть указатель инструкции, который отслеживает, где в его контексте он запущен.

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

То, что вы пытаетесь сделать так:

Последовательный запуск потоков, независимо от того, какой поток завершается первым, то есть это не multi-threading.Кроме того, использование lock.acquire() and lock.release() внутри каждой функции для лишает душу многопоточности

Ответ: если вы действительно хотите, чтобы потоки запускались последовательно, вам не следуетполучение и освобождение потоков внутри функций,

Небольшое изменение:

from termcolor import colored
import threading
import time
from random import randrange


def threadRed(n, tempo):
    for i in range(n):
        # lock.acquire()
        print(colored("red", 'grey', 'on_red', attrs=['dark', 'bold']))
        print(colored("I'm going to sleep for %d seconds," % tempo, 'red'))
        time.sleep(tempo)
        # lock.release()


def threadYellow(n, tempo):
    for i in range(n):
        # lock.acquire()
        print(colored("yellow", 'grey', 'on_yellow', attrs=['dark', 'bold']))
        print(colored("I'm going to sleep for %d seconds," % tempo, 'yellow'))
        time.sleep(tempo)
        # lock.release()


def threadGreen(n, tempo):
    for i in range(n):
        # lock.acquire()
        print(colored("green", 'grey', 'on_green', attrs=['dark', 'bold']))
        print(colored("I'm going to sleep for %d seconds," % tempo, 'green'))
        time.sleep(tempo)
        # lock.release()


lock = threading.Lock()
repeticoes = 5
lock.acquire()
tempo = randrange(1, 11)
t_red = threading.Thread(target=threadRed, args=(repeticoes, tempo))
tempo = randrange(1, 11)
t_yellow = threading.Thread(target=threadYellow, args=(repeticoes, tempo))
tempo = randrange(1, 11)
t_green = threading.Thread(target=threadGreen, args=(repeticoes, tempo))
lock.release()
t_red.start()
t_yellow.start()
t_green.start()
t_red.join()
t_yellow.join()
t_green.join()

ВЫХОД:

red
I'm going to sleep for 6 seconds,
yellow
I'm going to sleep for 4 seconds,
green
I'm going to sleep for 4 seconds,
yellow
I'm going to sleep for 4 seconds,
green
I'm going to sleep for 4 seconds,
red
I'm going to sleep for 6 seconds,
yellow
I'm going to sleep for 4 seconds,
green
I'm going to sleep for 4 seconds,
red
I'm going to sleep for 6 seconds,
...