为什么我的线程没有按我期望的方式运行?

Why do my threads not function the way I expect?

我想创建一个每隔一段时间执行一些任务的程序,比如每 4 秒一次,但这应该使用多个线程轮流完成,每个线程在允许另一个执行下一个任务之前执行一个任务。

如果每 4 秒打印一次是我想要执行的任务,事件的顺序可能如下所示。

Thread 1 printed at 0 seconds
Thread 2 printed at 4 seconds
Thread 3 printed at 8 seconds
Thread 1 printed at 12 seconds
...

我通过存储线程 ID 队列并将队列的第一个元素视为应该执行任务的下一个线程的 ID 来解决这个问题。当一个线程执行任务时,队列会旋转,以便另一个线程执行下一个任务。自上次任务完成以来的时间在每个线程中的每次迭代中计算,并用于确定线程是否应该执行任务(同时轮到当前线程)。

这是代码

from threading import Thread, Lock
import threading
from collections import deque
from datetime import datetime
import time

mutex = Lock()
print_interval = 4.0
thread_queue = deque([])
running = True

def print_thread():
    last_print_time = datetime.now()
    
    while running:
        mutex.acquire()
        delta_time = (datetime.now() - last_print_time).total_seconds()

        if delta_time >= print_interval and threading.get_ident() == thread_queue[0]:
            last_print_time = datetime.now()
            thread_queue.rotate(1)
            print('Thread {} printing at time {}'.format(threading.get_ident(), datetime.now().time()), flush=True)
        
        mutex.release()
        
threads = []

for i in range(4):
    thread = Thread(target = print_thread)
    thread.start()
    thread_queue.append(thread.ident)
    
time.sleep(10)

running = False
for thread in threads:
    thread.join()

这是一个输出示例。

Thread 29548 printing at time 17:11:50.662538
Thread 34616 printing at time 17:11:50.683628
Thread 35900 printing at time 17:11:50.683628
Thread 27924 printing at time 17:11:50.683628
Thread 29548 printing at time 17:11:54.667393
Thread 34616 printing at time 17:11:54.683969
Thread 35900 printing at time 17:11:54.683969

线程没有等待正确的时间过去,由于某种原因,delta_time 计算在上下文切换时爆炸,线程立即执行任务,只有在所有线程都完成时才会暂停完成任务。我的逻辑在这里正确吗?我不确定出了什么问题。

谢谢。

编辑:我将解释我认为 print_thread 应该 运行 的步骤,并尽量弄清楚它。假设我们有 2 个 ID 为 1 和 2 的线程,线程队列看起来像 [1,2](线程 1 先行)

Thread 1 acquires the lock
    delta_time is < 4
    conditional fails to execute
Thread 1 releases the lock

Thread 2 acquires the lock
    delta_time is < 4
    conditional fails to execute
Thread 2 releases the lock

This goes on for about 4 seconds...

Thread 1 acquires the lock
    delta_time is 4.1
    conditional is true because delta_time is >= 4 and this thread is at the front of the queue
    last_print_time = current time
    rotate queue (thread 2 will be next)
Thread 1 releases the lock

Thread 2 acquires the lock
    delta_time is 0.01
    conditional fails because not enough time has passed
Thread 2 releases the lock

抱歉,如果这很冗长,但这基本上是我期待的流程,以及为什么线程应该顺序执行,而不是立即执行。

至于我的主要问题是每个线程都使用自己的私有last_print_time并且它不会在其他线程中重置last_print_time

您将不得不使用 global last_print_time


带有全局变量的完整代码。

我设置了更长的时间 sleep() 来查看结果。

from threading import Thread, Lock
import threading
from collections import deque
from datetime import datetime
import time

mutex = Lock()
print_interval = 4.0
thread_queue = deque([])
running = True

last_print_time = datetime.now()

def print_thread():
    global last_print_time
    
    while running:
        mutex.acquire()
        delta_time = (datetime.now() - last_print_time).total_seconds()

        if delta_time >= print_interval and threading.get_ident() == thread_queue[0]:
            last_print_time = datetime.now()
            thread_queue.rotate(1)
            print('Thread {} printing at time {}'.format(threading.get_ident(), datetime.now().time()), flush=True)
        
        mutex.release()
        
threads = []

for i in range(4):
    thread = Thread(target = print_thread)
    thread.start()
    thread_queue.append(thread.ident)
    
time.sleep(30)

running = False
for thread in threads:
    thread.join()

结果:

Thread 140276746778368 printing at time 19:40:20.012389
Thread 140276517566208 printing at time 19:40:24.015615
Thread 140276729992960 printing at time 19:40:28.021712
Thread 140276738385664 printing at time 19:40:32.037404
Thread 140276746778368 printing at time 19:40:36.038693