Как эффективно выполнять 50 параллельных методов 500 раз в секунду?

Мне нужно выполнить strategy.AllTablesUpdated(); для 50 стратегий за 2 мс (и мне нужно повторить это ~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);
    }

Из журналов (в мкс) неудачная попытка потратила ~ 1 мс:

12: 55: 43: 778 Отладка: попытка TryEnter 1264 12:55:43:779 Отладка: ошибка TryEnter 2123

Из журналов (в мкс) успешная попытка затрачивается ~ 0,01 мс:

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 мс, если блокировка не получена)
  • Как хорошо было бы начать 50 Task каждые 2 мс = 25 000 задач каждую секунду? Может ли.NET эффективно управлять этим? Я также могу использовать шаблон производитель-потребитель с BlockingCollection и начать 50 "рабочих" только ОДИН РАЗ, а затем отправлять новый пакет из 50 предметов каждые 2 мс в BlockingCollection? Это было бы лучше?
  • Как бы вы выполнили 50 методов, которые можно выполнять параллельно каждые 2 мс (500 раз в секунду), всего 25 000 раз в секунду?

1 ответ

Решение
  1. Monitor.TryEnter(объект) - это просто Monitor.TryEnter(объект, 0, ref false) (время ожидания 0 миллисекунд). То, что 1 мс, если блокировка не получена, это просто накладные расходы на попытку получить блокировку.
  2. Вы можете запускать столько задач, сколько захотите, все они используют ThreadPool, хотя будет ограничено максимальным количеством потоков. Максимум зависит от вашей системы, количества ядер, памяти и т. Д. Это не будет 25 000 потоков, это точно. Однако, если вы начнете вмешиваться в планировщик TPL, у вас возникнут проблемы. Я бы просто использовал Parallel.Foreach и посмотрим, как далеко я это доберусь.
  3. Parallel.ForEach, Я также гарантирую, что strategies имеет тип IList так что многие элементы запускаются, насколько это возможно, без ожидания итератора.

Вы не вставили код в OnAllTablesUpdated(), вы сохраняете блокировку на время этой процедуры. Это будет вашим узким местом во всех отношениях.

Некоторые вопросы, почему вы используете блокировку, когда таблица готова к обработке?

  1. Делегаты не возможны?
  2. Зачем блокировать его, когда вы используете стратегию? Вы модифицируете эту таблицу внутри каждой стратегии? Вы не можете взять его копию, если это так?
Другие вопросы по тегам