2017-05-19 11 views
1

Pythonのメインアプレットのコードを修正することなく、テストしてうまくいけばデバッグするために作った小さなコードがあります。これは私がこのコードをビルドしてみましょうありますPythonスレッドで複数のstdoutを実行中

#!/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を使用します。なぜなら、(exapleのために)数字を表示し、それをフラッシュして古い場所に新しいものを印刷するのが好きだからです。したがって、単に印刷するためにすべての番号に対して新しい行を作成するのではなく、出力用に固定された場所を作成します。 – BlackVikingPro

答えて

0

各スレッドをstdoutに出力するのではなく、1つのスレッドでstdoutを排他的に制御する方が良い解決策です。次に、他のスレッドが出力するデータをディスパッチするためのスレッドセーフチャネルを提供します。

これを実現する良い方法の1つは、すべてのスレッド間で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() 

出力例:stdoutに

(Thread0:110) (Thread1:330) 
+0

私のためにいくつかのコードを書くことができますか? – BlackVikingPro

+0

@BlackVikingProすべて完了 – Aaron3468

+0

ありがとう! – BlackVikingPro

関連する問題