我编写了一小段代码来测试并希望调试问题,而无需修改 Python 主小程序中的代码。这让我可以构建这段代码:
#!/usr/bin/env python
import sys, threading, time
def loop1():
count = 0
while True:
sys.stdout.write('\r thread 1: ' + str(count))
sys.stdout.flush()
count = count + 1
time.sleep(.3)
pass
pass
def loop2():
count = 0
print ""
while True:
sys.stdout.write('\r thread 2: ' + str(count))
sys.stdout.flush()
count = count + 2
time.sleep(.3)
pass
if __name__ == '__main__':
try:
th = threading.Thread(target=loop1)
th.start()
th1 = threading.Thread(target=loop2)
th1.start()
pass
except KeyboardInterrupt:
print ""
pass
pass
我对这段代码的目标是能够让这两个线程同时以 stdout 格式显示输出(带有刷新),然后并排或其他。问题是我假设因为它正在刷新每个字符串,所以默认情况下它会刷新另一个字符串。如果可能的话,我不太知道如何让它发挥作用。
如果你只运行其中一个线程,它就可以正常工作。但是,我希望能够在终端输出中同时运行两个线程,并使用它们自己的字符串运行。这是一张显示我得到的图片:
终端截图
如果您需要更多信息,请告诉我。提前致谢。
与其让每个线程都输出到 stdout,更好的解决方案是让一个线程独占控制 stdout。然后为其他线程提供一个线程安全通道来调度要输出的数据。
实现这一目标的一个好方法是共享 Queue所有线程之间。确保只有输出线程在将数据添加到队列后才访问数据。
输出线程可以存储来自每个其他线程的最后一条消息,并使用该数据很好地格式化标准输出。这可以包括清除输出以显示类似的内容,并在每个线程生成新数据时更新它。
Threads
#1: 0
#2: 0
示例
做出了一些决定来简化此示例:
- 向线程提供参数时需要注意一些问题。
- 当主线程退出时,守护线程会自行终止。它们用于避免增加这个答案的复杂性。在长时间运行或大型应用程序上使用它们可能会带来问题。其他问题讨论how to exit a multithreaded application不会泄漏内存或锁定系统资源。您需要考虑您的程序需要如何发出退出信号。考虑使用
asyncio
来避免这些注意事项。
- 不使用换行符,因为
\r
回车符无法清除整个控制台。它们只允许重写当前行。
import queue, threading
import time, sys
q = queue.Queue()
keepRunning = True
def loop_output():
thread_outputs = dict()
while keepRunning:
try:
thread_id, data = q.get_nowait()
thread_outputs[thread_id] = data
except queue.Empty:
# because the queue is used to update, there's no need to wait or block.
pass
pretty_output = ""
for thread_id, data in thread_outputs.items():
pretty_output += '({}:{}) '.format(thread_id, str(data))
sys.stdout.write('\r' + pretty_output)
sys.stdout.flush()
time.sleep(1)
def loop_count(thread_id, increment):
count = 0
while keepRunning:
msg = (thread_id, count)
try:
q.put_nowait(msg)
except queue.Full:
pass
count = count + increment
time.sleep(.3)
pass
pass
if __name__ == '__main__':
try:
th_out = threading.Thread(target=loop_output)
th_out.start()
# make sure to use args, not pass arguments directly
th0 = threading.Thread(target=loop_count, args=("Thread0", 1))
th0.daemon = True
th0.start()
th1 = threading.Thread(target=loop_count, args=("Thread1", 3))
th1.daemon = True
th1.start()
# Keep the main thread alive to wait for KeyboardInterrupt
while True:
time.sleep(.1)
except KeyboardInterrupt:
print("Ended by keyboard stroke")
keepRunning = False
for th in [th0, th1]:
th.join()
示例输出:
(Thread0:110) (Thread1:330)
我是一名优秀的程序员,十分优秀!