如何使3个线程按顺序打印

时间:2019-02-08 11:39:17

标签: python multithreading synchronization locking semaphore

我需要制作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 :(得分:0)

好的,您希望输出会杀死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,

答案 1 :(得分:0)

请勿尝试使用threading.Lock()lock对象仅用于相互排斥(即,防止两个或多个线程同时访问相同的数据。)它不用于之间的通信线程。

IMO,最好的方法是使用三个Semaphore实例。 Python有一个类asyncio.Semaphore,但我对其文档中的“非线程安全”一词感到有些困惑。我从未使用过该类,但是它看起来像其他语言库中的信号量,用于在线程之间发信号。

信号量就像一个包含零个或多个许可的阻塞队列。许可证是抽象的;他们实际上不存在。信号量仅保留应该在任何给定时刻“包含”的信号量的计数。

呼叫者可以尝试acquire()许可,这将减少计数并在计数大于零时立即返回,否则将等待直到某个其他线程release()获得许可。< / p>

所以这是您的用法:

制作三个空的信号量(计数== 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(),然后它们应该以正确的顺序逐个开始运行。

答案 2 :(得分:0)

我做到了!

感谢大家的提示!但是我使用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()

答案 3 :(得分:0)

这是同一代码的另一个版本,但使用的是纯信号量,而不是事件

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