2

プライベート状態 (ConcurrentDictionary) を定期的に処理する必要があるクラスがあります。私はこれを経由してやっていTask.Factory.StartNew(doStuff)ます。このタスクはコレクションを変更するため、条件が true になったときに doStuff が 1 回だけ実行されるようにしたいと考えています。実行中の作業は競合状態を無視しても問題ありませんが、冗長なタスクがリソースを占有し、同期を締め出すことはできれば望んでいません。現在、問題なく動作する二重チェック ロックによって制御されていますが、メソッドの最後に追加するのは非常に冗長なコードです。

public void method()
{
    ...
    // do the method related stuff. Upon executing this method, the condition for
    // executing the task could become true, so it is appropriate to try to start it,
    // even though it is not directly related to the semantics of this method

    ...

    // now see if the task should be run
    if (clock.Now > timestamp.Plus(interval) && periodicTask == null)
    {
        lock (lockObject)
        {
            if (periodicTask == null) 
                periodicTask = Task.Factory.StartNew(this.DoStuff);
        }
    }
}
private void DoStuff()
{      
    doActualProcessing();

    //signal that task is complete
    timestamp = clock.Now;
    periodicTask = null;
}

このセットアップは、DoStuff が何度も呼び出されるのを防ぐために機能しますが、冗長すぎて少し汚れているように見えます。理想的には、この単一呼び出しロジックをカプセル化して、次のようなことができるようにしたいと考えています。

public void method()
{

    // do the method related stuff.
    ...

    // now see if the task should be run
    startTaskExactlyOnce(DoStuff);
}

私が見た唯一のオプションは、おそらくLazy<T>これを達成するために を使用することですが、ここでは適切ではないようです: 1. オブジェクトを初期化していない、タスクを実行している 2. タスクは定期的に実行される期間ごとに 1 回 3. タスクを開始する必要があるだけなのでLazy<t>.Value、実行を引き起こすために使用するための翻訳はありません。

4

3 に答える 3

2

個人的には、二重チェックのロック全体をパントします。あなたが支払うリスクプレミアムに対して実質的なものを買うことになるとは思いません。そうは言っても、あなたの特定の実装はおそらくうまくいくでしょう。しかし、これはほとんど偶然です。読む。

まず、1) x86 ハードウェアへの書き込みには既に揮発性セマンティクスがあり、2) 特別な同期ポイント、つまりこの場合は a の終わりで暗黙的なメモリ バリアが生成periodicTaskされるため、書き込みはすぐに発行されます。メモリ モデル環境では、書き込み側はおそらく問題ありません。DoStuffTask

第 2 に、システムから現在の時刻を抽出しようとして、( のように動作すると仮定して)の読み取りがおそらく最適化をすり抜けperiodicTaskてしまう可能性があります。methodclock.NowDateTime.Now

「おそらく」という言葉をどのように使い続けたかに注意してください。上記の結論を導き出す際に、いくつかの仮定がありました。私が完全に間違っている可能性があります。とはいえ、私の仮定が真実である可能性が最も高いと自信を持って言えます。問題は、なぜリスクを冒すかです。私が正しかったとしても、次のプログラマーがあなたの意図を理解していなかったために物事を切り替え始めたときに、このコードは簡単に壊れてしまう可能性があります。

まず、ダブルチェック ロック パターンの理由に戻りましょう。私が言ったように、それは本当に価値がありません。ではない場合、どのくらいの頻度methodで実行すると予想されますか? そのシナリオは、意味のある利益を達成する前に、他のすべてのシナリオを大幅に上回る必要があります (...私にはわかりません...おそらく 100,000 対 1 または何か)。のコストは非常に小さいので、どんなトリックをプレイしても、その努力を価値のあるものにするためには、非常に大きな費用対効果がなければなりません。あなたのシナリオではそれが起こっているとは思いません。periodicTasknulllock

于 2013-07-30T00:25:38.590 に答える
0

辞書を変更するスレッドを 1 つだけにしたい場合、なぜ並行実装を使用するのですか? 私には、タイマーが必要なだけのようです。または、処理メソッドの最後に次の実行をスケジュールできます。

于 2013-07-29T19:04:36.047 に答える