2

現在、Python (2.7) を使用して、いくつかのスレッドが進行中の GUI を作成しています。情報を取得する前に約 1 秒の遅延を行う必要があるという点に遭遇しましたが、関数の実行に数ミリ秒以上かかる余裕はありません。timer.doneFlag それを念頭に置いて、フラグを設定し、それが完了したかどうかを確認するために突っ込み続ける主な機能を持つスレッドタイマーを作成しようとしています。

それは働いています。しかし、いつもではありません。time.sleep私が直面している問題は、 の関数がrun1 秒も完全に待機していないように感じることがあるということです(場合によっては、待機さえしないこともあります)。必要なのは、開始時間を制御し、1 秒に達したときにフラグを上げるフラグを設定できることだけです。

スレッド化可能な遅延を取得するためだけにやりすぎている可能性があります。何か提案したり、次のコードのバグを見つけるのを手伝ってくれたりすると、とても感謝しています!

私が使用したコードの一部を添付しました:

メインプログラムから:

class dataCollection:
    def __init__(self):
        self.timer=Timer(5)
        self.isTimerStarted=0  
        return

    def StateFunction(self): #Try to finish the function within a few milliseconds

        if self.isTimerStarted==0:
           self.timer=Timer(1.0)
           self.timer.start()
           self.isTimerStarted=1

        if self.timer.doneFlag:
           self.timer.doneFlag=0
           self.isTimerStarted=0
           #and all the other code



import time
import threading
class Timer(threading.Thread):          
    def __init__(self, seconds):            
        self.runTime = seconds          
        self.doneFlag=0
        threading.Thread.__init__(self)
    def run(self):      
        time.sleep(self.runTime)    
        self.doneFlag=1
        print "Buzzzz"

x=dataCollection()
while 1:
    x.StateFunction()
    time.sleep(0.1)
4

1 に答える 1

0

まず、threading.Timer柔軟性の低い状態で効果的に再構築しました。したがって、既存のクラスを使用する方がよいと思います。(タイマー インスタンスごとにスレッドを作成することには明らかな欠点がいくつかあります。ただし、1 つのワンショット タイマーだけが必要な場合は問題ありません。)

さらに重要なことに、メイン スレッドで繰り返しポーリングdoneFlagを行うことは、おそらく悪い考えです。これは、状態関数をできるだけ頻繁に呼び出す必要があり、正当な理由もなく CPU を消費することを意味します。

おそらく、数ミリ秒以内に戻らなければならない理由は、おそらく GUI のために、ある種のイベント ループに戻っているためです (ただし、たとえば、ネットワーク リアクターには同じ問題があり、同じ解決策があるため、物事を一般的にしてください)。

その場合、そのようなイベント ループのほとんどすべてには、イベント ループ内で時間指定されたコールバックをスケジュールする方法 ( <code>Timer in wxcallLaterintwistedなど) があります。したがって、それを使用します。

そのようなものを持たないフレームワークを使用している場合は、少なくとも、イベントを送信する/シグナルを発する/メッセージを投稿する/外部から呼び出されるものは何でも、何らかの方法があることを願っています。(単純なファイル記述子ベースのリアクタの場合、それがないかもしれませんが、パイプをリアクタに放り込むだけで自分で追加できます。)したがって、Timerコールバックを変更して、イベント ループを通知するコードを記述する代わりに、をポーリングしTimerます。

何らかの理由で、スレッド間で共有される変数を本当にポーリングする必要がある場合は、本当に、Conditionまたはで保護する必要がありますRLock。言語には、スレッド 0 が値を更新したときに、スレッド 1 が新しい値をすぐに、またはそれ以降に見るという保証はありませ。CPython (の特定のバージョン) の内部構造を十分に理解していれば、GIL が特定のケースでロックを不要にしていることを証明できることがよくあります。しかし、そうでなければ、これはレースです。

ついに:

私が遭遇する問題は、 run の time.sleep 関数が 1 秒間完全に待機していないように感じることがあります (待機しない場合もあります)。

ドキュメントには、これが発生する可能性があることが明確に記載されています。

実際の一時停止時間は、要求された時間よりも短い場合があります。これは、キャッチされたシグナルは、そのシグナルのキャッチ ルーチンの実行後に sleep() を終了するためです。

したがって、実際に少なくとも 1 秒間スリープすることを保証する必要がある場合、これを行う唯一の方法は次のようなものです。

t0 = time.time()
dur = 1.0
while True:
    time.sleep(dur)
    t1 = time.time()
    dur = 1.0 - (t1 - t0)
    if dur <= 0:
        break
于 2013-03-20T21:04:42.937 に答える