Следует ли создавать события в новых потоках, чтобы не блокировать текущую работу? - PullRequest
1 голос
/ 15 декабря 2009

В настоящее время я разрабатываю сборку, которая будет использоваться третьими лицами. Один из классов имеет длительный процесс TCP-соединений и информирует о своем процессе, используя события. Например

''# Do stuff that takes some time
RaiseEvent CompletedFirstPartEvent()
''# Do stuff that takes some time
RaiseEvent CompletedSecondPartEvent()
''# Do stuff that takes some time
RaiseEvent CompletedSecondPartEvent()

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

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

Что бы вы сделали? Создать новый поток или заставить пользователя создать свой собственный поток? (Или - есть лучший подход, которого я не знаю?)

Заранее спасибо.

Ответы [ 6 ]

2 голосов
/ 15 декабря 2009

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

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

2 голосов
/ 15 декабря 2009

Мы столкнулись с тем же при создании WebSync - как вы допускаете длительные процессы в пользовательском коде, не жертвуя своим приложением?

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

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

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

1 голос
/ 15 декабря 2009

Это может быть хорошее использование Threadpool


Ваш "Делай вещи" кажется длинным с некоторыми редкими уведомлениями о событиях. Вам нужно какое-то уведомление «запустить и забыть» и быть уверенным, что вызываемые делегаты не загромождают вас (они могут занять слишком много времени и / или вызвать исключение).

  • Создать ветку для каждого опубликованного мероприятия может быть дорого.

  • BackgroundWorkers полезны только для уведомлений с графическим интерфейсом (WinForms).

Почему бы не использовать Threadpool? Это дешево и изолирует вас от девиантного поведения.

1 голос
/ 15 декабря 2009

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

1 голос
/ 15 декабря 2009

У меня есть класс Collector, который открывает «сырой» сокет и собирает данные из локальной сети. Внутри класса Collector чтение сокетов выполняется потоком Receiver. Этот поток запускает событие InternalPacketReceived для каждого пакета, считываемого из сети. Также внутри класса Collector у меня также есть поток Distributor, который подписывается на событие InternalPacketReceived получателя. Пакеты, полученные обработчиком распространителя, добавляются во внутреннюю очередь пакетов. Затем поток распространителя отвечает за то, чтобы сделать пакеты в очереди доступными для подписчиков общедоступного события Collector PacketReceived. Таким образом, если поток распространителя остановлен длительным обработчиком, получатель продолжает читать пакеты без задержки.

С точки зрения пользователя, он взаимодействует с открытым интерфейсом в классе Collector - Start (), Stop (), подписывается на событие PacketReceived и т. Д. За кулисами Collector использует два потока - Receiver и Distributor - для Избегайте проблем, создаваемых долго работающими обработчиками.

Надеюсь, это понятно.

1 голос
/ 15 декабря 2009

почему вы не используете backgroundworker?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...