Быстрое создание тысяч потоков и одновременное их выполнение - PullRequest
6 голосов
/ 13 октября 2010

У меня есть приложение на C # .NET, которое должно сообщать от 4000 до 40000 подключенных устройств, чтобы выполнить задачу одновременно (или как можно ближе к одновременной работе).

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

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

Я все еще хочу лучшую производительность, и именно поэтому я здесь.Есть идеи?Комментарии?Предложение?Спасибо.

-Shaun

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

Ответы [ 7 ]

14 голосов
/ 13 октября 2010

Двухъядерный гиперпоточный процессор МОЖЕТ иметь возможность выполнять 4 потока одновременно - в зависимости от того, что делает поток (нет конфликтов по IO или доступу к памяти и т. Д.) Четырехъядерный Hyperthread, возможно, 8. Но 40K просто не может быть физически.

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

Или посмотрите в другом месте. Как SB рекомендует в комментариях, используйте многоадресную передачу UDP, чтобы уведомить прослушивающие машины, что они должны что-то делать.

12 голосов
/ 13 октября 2010

Вы не можете одновременно выполнять 4000 потоков, не говоря уже о 40k. В лучшем случае на настольном компьютере с гиперпоточностью вы можете запустить до 8 одновременных процессов (это предполагает четырехъядерный процессор). Потоки псевдопараллельны, и это даже не касается проблем состязания шины.

Если вам абсолютно необходимо одновременность для устройств 40 КБ, вам нужна некоторая форма аппаратной синхронизации.

5 голосов
/ 13 октября 2010

Похоже, у вас есть некоторый контроль над тем, какое программное обеспечение работает на каждом устройстве. В этом случае вы можете обратиться к использованию HPC и иерархически спроектировать свои устройства (узлы) и / или использовать MPI для выполнения ваших удаленных процессов.

Для примера иерархии: назначьте, скажем, 8 узлов в качестве основных мастеров, опять же, с 8 подчиненными узлами, каждый подчиненный может выступать в качестве ведущего также с 8 подчиненными (для этого может потребоваться алгоритм автоматической подписки). Вы будете иметь иерархию 6 в глубину, чтобы покрыть 40000 узлов. У каждого мастера есть небольшая часть кода, работающая постоянно, ожидая инструкций для передачи рабам.

Все, что вы затем делаете, это передаете инструкцию 8 основным мастерам, и ваши инструкции будут передаваться мастерам в «кластер» по проводам асинхронно. Инструкция должна быть передана максимум 5 раз и, таким образом, будет распространена очень быстро.

В качестве альтернативы (или в сочетании) вы можете взглянуть на MPI, который является нерегулярным решением. Есть несколько установленных реализаций C #.

4 голосов
/ 13 октября 2010

Затраты на создание тысяч потоков (очень) значительны;Я бы искал альтернативное решение.Это похоже на работу для асинхронного ввода-вывода: ваш компьютер предположительно имеет только одно сетевое соединение, поэтому за один раз можно отправить не более одного сообщения - потоки не могут улучшить это!

3 голосов
/ 13 октября 2010

Правильно ли я предположил, что вы используете синхронный вызов API на своем устройстве, поэтому он должен выполняться в потоке?Есть ли у API асинхронная версия вызова?Если API устройства действительно может поддерживать устройства с разрешением более 40 тыс., То так и должно быть.Он также должен иметь внутреннюю обработку любых дескрипторов ожидания (или эквивалентных), необходимых для синхронизации возвращаемых данных для обратного вызова.Это не то, что вы можете обработать на стороне клиентского приложения;у вас недостаточно видимости базовой реализации API устройства, чтобы знать, как распараллеливать задачи.Как вы обнаружили, создание 40 тыс. Потоков с блокировкой вызовов не сокращает его.

2 голосов
/ 03 ноября 2015

Всегда весело с этими старыми.

1 МБ на поток означает, что вам нужно 4-40 ГБ только в ОЗУ как минимум, и 4k-40k ядер.и тот факт, что у вас есть сеть для отправки на нее.

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

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

Вы просто не можете победить физическое царство (пока ...).

2 голосов
/ 13 октября 2010

Вы должны сделать асинхронный ввод-вывод для устройств. Это очень эффективно и использует другой (больший) набор потоков для обработки некоторой работы. Конечно, устройства будут получать команды намного быстрее. Пул потоков ввода-вывода будет обрабатывать ответы (если есть)

...