Производительность ввода-вывода - async vs TPL vs Dataflow vs RX

У меня есть кусок кода С# 5.0, который генерирует тонну сетевого и дискового ввода-вывода. Мне нужно запустить несколько копий этого кода параллельно. Какая из следующих технологий, скорее всего, даст мне лучшую производительность:

  • асинхронные методы с ожиданием

  • напрямую использовать задачу из TPL

  • TPL Dataflow nuget

  • Реактивные расширения

Я не очень хорошо разбираюсь в этом параллельном материале, но если использовать нижний рычаг, например, Thread, может дать мне намного лучшую производительность, я бы тоже подумал об этом.

Ответ 1

Любая разница в производительности между этими параметрами была бы несущественной в свете "тонны сетевого и дискового ввода-вывода".

Лучше задать вопрос: "Какой вариант легче всего изучать и развивать?" Или "какой вариант лучше всего будет поддерживать этот код через пять лет?" И для этого я бы предложил сначала async, или Dataflow или Rx, если ваша логика лучше представлена ​​как поток.

Ответ 2

Это похоже на попытку оптимизировать длину вашего трансатлантического полета, попросив самый быстрый способ снять ремень безопасности.

Хорошо, некоторые реальные советы, так как я был вроде рывком

Позвольте дать полезный ответ. Подумайте о производительности, как в "Классах" действий - каждый на порядок медленнее (по крайней мере!):

  • Доступ только к ЦП, очень мало использования памяти (т.е. рендеринг очень простой графики на очень быстрый графический процессор или вычисление цифр Pi)
  • Доступ только к ЦП и в памяти, ничего на диске (то есть хорошо написанная игра)
  • Доступ к диску
  • Доступ к сети.

Если вы выполняете даже один действия №3, нет смысла делать оптимизации, типичные для действий № 1 и № 2, как оптимизация библиотек потоков, - они полностью омрачены ударом диска. То же самое и для трюков процессора - если вы постоянно сталкиваетесь с пропущенными кешами L2/L3, экономя несколько циклов процессора с помощью сборки вручную, это не стоит (вот почему такие вещи, как loop unrolling, как правило, плохая идея в эти дни).

Итак, что мы можем извлечь из этого? Есть два способа ускорить работу вашей программы: перейдите от # 3 до # 2 (что не всегда возможно, в зависимости от того, что вы делаете), или делая меньше ввода-вывода. Скорость ввода-вывода и скорость сети - это фактор ограничения скорости в большинстве современных приложений, и именно этого вы должны оптимизировать.

Ответ 3

Это более старый вопрос, но для тех, кто читает это...

Это зависит. Если вы попытаетесь насытить связь 1Gbps с сообщениями 50B, вы будете связаны с ЦП даже с простой неблокирующей отправкой по сырым сокетам. Если, с другой стороны, вы довольны пропускной способностью 1 Мбит/с или ваши сообщения больше 10 КБ, любая из этих фреймворков выполнит эту работу.

В ситуациях с низкой пропускной способностью я бы рекомендовал установить приоритет по простоте использования, то есть async/await, Dataflow, Rx, TPL в этом порядке. Обратите внимание, что приложение с высокой пропускной способностью должно быть прототипировано, как если бы оно было малополосным и оптимизировано позже.

Для истинного приложения с высокой пропускной способностью я могу рекомендовать Dataflow над Rx, потому что Rx не предназначен для высоких concurrency. Raw TPL - это нижний уровень, который гарантирует минимальные накладные расходы, если вы можете справиться со сложностью. Если вы можете эффективно использовать выделенные потоки, это будет еще быстрее. Async/await и Dataflow IMO не влияет на производительность. Накладные расходы кажутся сопоставимыми, поэтому выберите тот, который лучше подходит.