Синхронизация Vs. Производительность Async Sockets в .NET.

Все, что я читал о сокетах в .NET, говорит о том, что асинхронный шаблон дает лучшую производительность (особенно с новым SocketAsyncEventArgs, который сохраняет выделение).

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

Но в моем приложении я клиент, и мне просто нужно прослушивать один сервер, отправляющий данные о рыночных тиках по одному подключению tcp. Прямо сейчас я создаю один поток, устанавливаю приоритет "Самый высокий" и вызываю его с помощью Socket.Receive(). Мой поток блокирует этот вызов и просыпается после поступления новых данных.

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

  • Потоки threadpool будут иметь приоритет по умолчанию, поэтому кажется, что они будут строго хуже моего собственного потока, который имеет самый высокий приоритет.

  • В какой-то момент мне все равно придется отправлять все через один поток. Скажем, что я получаю N обратных вызовов почти в одно время на N различных потоков threadpool, уведомляя меня о новых данных. N-байтовые массивы, которые они доставляют, не могут обрабатываться в потоковых потоках, потому что нет гарантии, что они представляют N уникальных сообщений о рыночных данных, поскольку TCP основан на потоке. Мне придется заблокировать и поместить байты в массив в любом случае и передать сигнал другому потоку, который может обрабатывать то, что в массиве. Поэтому я не уверен, что с N потоками нитей покупает меня.

Я думаю об этом неправильно? Есть ли причина использовать асинхронный patter в моем конкретном случае одного клиента, подключенного к одному серверу?

UPDATE:

Итак, я думаю, что я неправильно понял асинхронный шаблон в (2) выше. Я бы получил обратный вызов в одном рабочем потоке, когда были доступны данные. Тогда я бы начал новый асинхронный прием и получил еще один обратный вызов и т.д. Я бы не получил N обратных вызовов одновременно.

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

Ответ 1

Самая медленная часть вашего приложения будет сетевой. Очень вероятно, что вы практически не измените производительность для одного потока, одного клиента соединения, изменив такие вещи. Сама коммуникация сети будет затмевать все другие вклады в обработку или время переключения контекста.

Скажем, что я получаю N обратных вызовов почти то же время на N разных threadpool нити сообщают мне, что есть новые данные.

Почему это произойдет? Если у вас есть один сокет, вы Begin выполняете операцию по его получению данных, и вы получите ровно один обратный вызов, когда это будет сделано. Затем вы решаете, нужно ли выполнять другую операцию. Похоже, вы слишком себя чувствуете, хотя, возможно, я упрощаю это в отношении того, что вы пытаетесь сделать.

Вкратце, я бы сказал: выберите простейшую модель программирования, которая доставит вам то, что вы хотите; учитывая выбор, доступный в вашем сценарии, они вряд ли будут иметь заметную разницу в производительности в зависимости от того, с кем вы столкнулись. С блокирующей моделью вы "теряете" поток, который может выполнять какую-то реальную работу, но эй... может быть, у вас нет настоящей работы для этого.

Ответ 2

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

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

Ответ 3

Этот класс был специально разработан для приложений сетевого сервера, требующих высокой производительности."

Как я понимаю, вы здесь клиент, имея только одно соединение.
Данные по этому соединению поступают в порядке, потребляемом одним потоком.

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


Вам действительно не нужно ускорять это, вы, вероятно, не можете.

Что вы можете сделать, однако, это отправлять рабочие единицы в другие потоки после их получения. Для этого вам не нужен SocketAsyncEventArgs. Это может ускорить процесс.

Как всегда, измерять и измерять. Кроме того, только потому, что вы можете, это не значит, что вы должны. Если производительности в обозримом будущем достаточно, то почему это осложняет ситуацию?