質問

私は、指定された時間のために実行している遅延する必要があるメソッドを持っています。

私が使うべき

Thread thread = new Thread(() => {
    Thread.Sleep(millisecond);
    action();
});
thread.IsBackground = true;
thread.Start();

または

Timer timer = new Timer(o => action(), null, millisecond, -1);

私はいくつかの<のhref = "http://msmvps.com/blogs/peterritchie/archive/2007/04/26/thread-sleep-is-a-sign-of-a-poorly-designed-を読んでいましたprogram.aspx」relが= "noreferrer"> Thread.Sleepの使用についての記事のは悪いデザインです。しかし、私は本当に理由を理解していません。

しかし、タイマーを使用するため、タイマーは、メソッドを処分しています。実行が遅れているので、私はタイマーを配置する方法がわかりません。あなたが何か提案はありますか?

それとも、遅延実行のための代替コードを持っている場合も感謝されます。

役に立ちましたか?

解決

1つの違いはSystem.Threading.Timerではなく、新しいスレッドを毎回作成するよりも、スレッドプールのスレッドでコールバックをディスパッチするということです。あなたのアプリケーションの寿命の間、複数回行われるように必要がある場合、これは、それがするので、(あなたが参照する記事が指摘するように、非常にリソースを消費しているプロセスを)スレッドの束を作成し、破壊のオーバーヘッドを保存しますただ、プール内のスレッドを再利用し、あなたはそれはあなたが(これもかなりのリソースを節約する)一度に実行されている少数のスレッドを持っていることを意味し、一度に行く複数のタイマーを持つことになります。

言い換えれば、Timerは、はるかに効率的になるだろう。 Thread.Sleepだけあなたは(OSがはるかに長いためにスリープ状態にしたりして)指定した時間の量と少なくとも同程度長く待つことが保証されているのでそれはまた、より正確かもしれません。確かに、Timerはまだ正確に正確であることを行っていないが、これは必ずしもThread.Sleepの意図するところではないのに対し、意図は、可能な限り、指定した時間に近いコールバックを発射することです。

あなたがパラメータとしてTimer自体を渡すと、私はこれを試していないのに(コールバックでのDisposeを呼び出すことができるかもしれのでTimerを破壊するとして、コールバックは、パラメータを受け入れることができます - 私はそれが可能だと思います)タイマは、コールバック時にロックされるかもしれない。

編集:いいえ、私はあなたがTimerコンストラクタ自体にコールバックパラメータを指定する必要があるため、あなたが、これを行うことはできませんと思います。

たぶん、このような何か? (ここでも、実際にそれを試していない)

class TimerState
{
    public Timer Timer;
}

...と、タイマーを開始します:

TimerState state = new TimerState();

lock (state)
{
    state.Timer = new Timer((callbackState) => {
        action();
        lock (callbackState) { callbackState.Timer.Dispose(); }
        }, state, millisecond, -1);
}

ロック前Timerフィールドが設定されていたこと、タイマーを解放しようとしているから、タイマーコールバックを防ぐ必要があります。

<時間>

補遺:コメンターが指摘したようにaction()はUIで何かをする場合、それはUIスレッド上でコールバックを実行するために、し、System.Windows.Forms.Timerを使用して、おそらくより良い賭けです。これがケースではありません、それはThread.SleepThreading.Timerするダウンだ場合は、Threading.Timerは移動するための方法である。

他のヒント

私はあなたが本当に指定された時間のためのアプリケーションを一時停止する場合のThread.sleepは罰金だと思います。私は、ほとんどの状況で人々が実際にアプリケーションが一時停止したくないので、人々はそれが悪いデザインであると言う理由があると思います。

たとえば、私はプログラマはソケットがメールを取得している間に待機するのThread.sleep(1000)を使用していたPOP3クライアントに取り組んでいました。その状況では、ソケットが完了した後にソケットと継続的なプログラムの実行にイベントハンドラをフックアップすることをお勧めします。

私はエリックの1に似たソリューションを実装覚えています。 しかしこれは作業1である。)

class OneTimer
    {
        // Created by Roy Feintuch 2009
        // Basically we wrap a timer object in order to send itself as a context in order to dispose it after the cb invocation finished. This solves the problem of timer being GCed because going out of context
        public static void DoOneTime(ThreadStart cb, TimeSpan dueTime)
        {
            var td = new TimerDisposer();
            var timer = new Timer(myTdToKill =>
            {
                try
                {
                    cb();
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(string.Format("[DoOneTime] Error occured while invoking delegate. {0}", ex), "[OneTimer]");
                }
                finally
                {
                    ((TimerDisposer)myTdToKill).InternalTimer.Dispose();
                }
            },
                        td, dueTime, TimeSpan.FromMilliseconds(-1));

            td.InternalTimer = timer;
        }
    }

    class TimerDisposer
    {
        public Timer InternalTimer { get; set; }
    }

System.Timerと私が持っている唯一の牛肉は、私はそれがポーリングサービスや開発における長い遅延(時間、分)のために使用さ見ている時間のほとんどは、多くの場合、イベントを起動するのを忘れていることであるの前にの彼らは、タイマーを起動します。これは私がアプリやサービスを開始した場合、私はそれが実際に実行される前に経過するタイマー(時間、分)まで待たなければならないことを意味します。

確かに、これはタイマーの問題ではありませんが、私はそのはしばしば誤用にそのあまりにも簡単なためで不適切に使用していると思います。

@miniscalopeありませんが、代わりに、タイマーのThreadPool.RegisterWaitForSingleObject使用していない、System.Threading.Timerが待つ、時間が経過すると、待機ハンドルを必要としないとき、スレッドプールのスレッド上で実行されるコールバックをキューに入れます単一のオブジェクトは、スレッドがコールバックを呼び出す前に合図するか、タイムアウトが期限切れにイベントを待っているスレッドプールスレッドをタイアップされます。

scroll top