2017-05-19 96 views
1

我有一小段代碼用於測試,希望能夠調試該問題,而無需修改我的主要applet中的代碼。這已經讓我建立這個代碼:在Python線程中執行多個stdout w/flush

#!/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 

我這段代碼的目標是能夠同時擁有這些線程在同一時間標準輸出格式(帶沖洗)顯示輸出,並具有然後並排或者其他的東西。問題是我假設它正在刷新每一個,它默認刷新另一個字符串。如果甚至有可能,我不知道如何讓這個工作。

如果你只是運行其中一個線程,它工作正常。不過,我希望能夠在終端輸出中同時運行兩個線程,並使用自己的字符串同時運行。這裏是一個圖片顯示什麼我越來越:

終端截圖

讓我知道如果你需要更多的信息。提前致謝。

+1

打印到標準輸出不是線程安全的。使用'logging'模塊,實現某種鎖定,或將打印移動到另一個線程。 – Blender

+0

我使用stdout是因爲我喜歡它將如何顯示(例如)一個數字,然後刷新它並在舊的地方打印一個新數字。因此,爲輸出創建一個固定位置,而不是爲每個數字創建一個新行以便打印它。 – BlackVikingPro

回答

0

而不是允許每個線程輸出到標準輸出,更好的解決方案是有一個線程控制標準輸出專門。然後爲其他線程提供一個線程安全通道來分派要輸出的數據。

實現此目的的一個好方法是在所有線程之間共享一個Queue。確保只有輸出線程在將數據添加到隊列後才能訪問數據。

輸出線程可以存儲來自每個其他線程的最後一條消息,並使用該數據很好地格式化stdout。這可以包括清除輸出以顯示類似內容,並在每個線程生成新數據時更新它。

Threads 
#1: 0 
#2: 0 

注意,有在傳遞參數給線程一些陷阱,以及我使用一些技巧,以確保安全出口,如使線程守護進程。不使用換行符,因爲\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) 
+0

你能爲我寫一些代碼嗎? – BlackVikingPro

+0

@BlackVikingPro全部完成 – Aaron3468

+0

非常感謝! – BlackVikingPro