2

2ミリ秒で50の戦略を実行する必要がありstrategy.AllTablesUpdated();ます(そして、1秒間に約500回繰り返す必要があります)。以下のコードを使用して、Monitor.TryEnter呼び出しに最大1ミリ秒(!!!)かかることがわかりました。これを50回行います。

    // must be called ~500 times per second
    public void FinishUpdatingTables()
    {
        foreach (Strategy strategy in strategies)   // about ~50, should be executed in 2 ms
        {
            // this slow and can be paralleled
            strategy.AllTablesUpdated();
        }
    }

...................。

    public override bool AllTablesUpdated(Stopwatch sw)
    {
        this.sw = sw;
        Checkpoint(this + " TryEnter attempt ");
        if (Monitor.TryEnter(desiredOrdersBuy))
        {
            Checkpoint(this + " TryEnter success ");
            try
            {
                OnAllTablesUpdated();
            } finally
            {
                Monitor.Exit(desiredOrdersBuy);
            }
            return true;
        } else
        {
            Checkpoint(this + " TryEnter failed ");
        }
        return false;
    }

    public void Checkpoint(string message)
    {
        if (sw == null)
        {
            return;
        }
        long time = sw.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L));
        Log.Push(LogItemType.Debug, message + time);
    }

ログ(µs単位)から、失敗した試行には約1ミリ秒かかります。

12:55:43:778デバッグ:TryEnterの試行1264 12:55:43:779デバッグ:TryEnterが失敗しました2123

ログ(µs単位)から、成功の試行には約0.01msが費やされます。

12:55:49:701デバッグ:TryEnterの試行889 12:55:49:701デバッグ:TryEnterの成功900

Monitor.TryEnterだから今、それは私が50の戦略のために一つずつ実行するには高すぎると思います。だから私はこのようなものを使ってこの仕事を並行させたいと思いTaskます:

    // must be called ~500 times per second
    public void FinishUpdatingTables()
    {
        foreach (Strategy strategy in strategies)  // about ~50, should be executed in 2 ms
        {
            // this slow and can be paralleled
            Task.Factory.StartNew(() => {
                strategy.AllTablesUpdated();
            });
        }
    }

Monitor.TryEnterまた、そのようなアプローチと同じlockように、すべてが非同期になるように置き換えることもできます。

私の質問:

  • なぜMonitor.TryEnterそんなに遅いのですか?(ロックが取得されていない場合は1ミリ秒)
  • 2ミリ秒ごとに50を開始するのはどれくらい良いでしょうかTask=毎秒25000のタスク?.NETはこれを効果的に管理できますか?また、生産者/消費者パターンを使用してBlockingCollection、50人の「労働者」を1回だけ開始し、2ミリ秒ごとに50個のアイテムの新しいパックをBlockingCollectionに送信することもできますか?それは良いでしょうか?
  • 2ミリ秒ごとに並列化できる50のメソッド(1秒あたり500回)をどのように実行しますか?合計で1秒あたり25000回ですか?
4

1 に答える 1

4
  1. Monitor.TryEnter(object) は単なる Monitor.TryEnter(object, 0, ref false) (0 ミリ秒のタイムアウト) です。ロックが取得されない場合の 1 ミリ秒は、ロックを取得しようとするオーバーヘッドにすぎません。
  2. 好きなだけタスクを開始できます。それらはすべて ThreadPool を使用しますが、スレッドの最大数に制限されます。最大値は、システム、コア数、メモリなどによって異なります...確かに 25,000 スレッドにはなりません。ただし、TPL スケジューラーをいじり始めると、問題が発生します。私はただ使っParallel.Foreachて、それがどこまで私を得るかを見たいと思います.
  3. Parallel.ForEach. また、イテレータを待たずにできるだけ多くのアイテムが起動されるように、それstrategiesが型であることを確認します。IList

コードを OnAllTablesUpdated() に貼り付けていないため、その手順の間ロックを保持します。それはあらゆる可能性であなたのボトルネックになるでしょう。

いくつか質問があります。テーブルを処理する準備ができたときにロックを使用するのはなぜですか?

  1. 代理はできませんか?
  2. 戦略を実行しているときにロックするのはなぜですか?各戦略内のテーブルを変更していますか? その場合、コピーをとっていただけないでしょうか。
于 2012-04-18T09:48:32.347 に答える