2011-01-11 1 views
7

Можно ли выполнять тяжелую обработку в асинхронных обратных вызовах .NET, заставляя их за несколько секунд до возвращения? Или я лишу OS/время выполнения важных ресурсов?Хорошо выполнять тяжелую обработку в асинхронных обратных вызовах?

Например, TcpListener.BeginAcceptSocket. Мой обратный вызов начинается с вызова EndAcceptSocket, а затем тратит время на получение данных и только затем закрывает сокет и возвращается. Это то, как оно предназначалось для использования, или я ожидаю, что сделаю дополнительную обработку в своей собственной теме?

+0

Я хотел бы призвать вас взглянуть на Rx (Реактивные расширения), что делает асинхронное программирование красивой вечернюю прогулку в парке! http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx – gideon

+0

Некоторые полезные ссылки Rx: http://rxwiki.wikidot.com/ Вот небольшой код, который я написал для асинхронного обновления списка каждый раз, когда я печатаю в текстовом поле, и запустите его на 0,5 секунды. См .-> http://stackoverflow.com/questions/4655619/simple-rx-code-silently-fails-in-windows-forms-only-during-debugging-in-visual-st – gideon

ответ

1

Да, это асинхронные сокеты (клиент Tcp, прослушиватели и т. Д.) Предназначены для использования. Вы всегда должны убедиться, что вы вызываете метод end aysnc, а затем выполняете любую необходимую обработку. Не ссылаясь на методы EndAccept(), EndSEnd(), EndReceive() и т. Д. И т. Д., Вы оставляете потенциально доступным для утечки памяти, поэтому всегда следует следовать хорошей практике.

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

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

Я делаю то же самое на своем коде сервера (смешанный с некоторыми другими WCF для промежуточного программного обеспечения и бэкэнд-коммуникационных элементов), и это наиболее масштабируемое сообщение, которое мы использовали. Вам нужно будет сделать Google, но есть парень, который опубликовал свое тестирование с использованием этой технологии, и он смог поддерживать 1000 одновременных сообщений на сервере с только 11 потоками. Неплохо.

пример сервера из MS: http://msdn.microsoft.com/en-us/library/fx6588te.aspx

пример клиента от MS: http://msdn.microsoft.com/en-us/library/bew39x2a.aspx

Это займет больше, чем это, чтобы получить его «усовершенствовали», но это хорошее место, чтобы начать.

+1

Статья в http: // www.codeproject.com/KB/threads/threadtests.aspx, похоже, указывает на то, что .NET ThreadPool имеет проблемы с производительностью, если вы долго обрабатываете потоки потоков потоков (такие как обработчики завершения асинхронного вызова). Эта проблема не была видна для вас? – Sander

+0

Я не могу действительно говорить с очень длинными временами обработки, но с точки зрения Socket-связи у нас никогда не было никаких проблем. Все наши сообщения следуют за буферизованным асинхронным подходом и даже большой передачей ... говорят, что данные, которые на мобильной платформе могут занять много времени, пока сеть прочная, сокеты оказались надежными. По иронии судьбы, почти каждая технология коммуникационных сетей использует сокеты под более высокой абстракцией для обработки тяжелой работы (как правило, не доступна на мобильных устройствах). – BonanzaDriver

+0

@Sander: В 2003 году ThreadPool имел по умолчанию 25 потоков на процессор (и большинство компьютеров были одноядерными). Теперь значение по умолчанию - 250 на процессор, поэтому есть меньше проблем, чем раньше: http://msdn.microsoft.com/en-us/library/system.threading.threadpool(v=VS.90).aspx (и .net 4 берет его до 1023 за процессор на 32 бит и 32768 за процессор на 64 бит!) –

1

Я повторил эксперименты CodeProject article on this topic и нашел результаты для .NET 4 похожими на то, что было описано в 2003 году. Обратите внимание, что в статье фактически не перечислены результаты для проблемного раздела, но, как я понимаю, основной вопрос все еще существует.

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

Тест попытается использовать 10 параллельных потоков, чтобы считать, насколько это возможно, через 1 секунду.

Использования 10 фоновых нитей (т.е. new Thread())

 
T0 = 4451756 
T1 = 4215159 
T2 = 5449189 
T3 = 6244135 
T4 = 3297895 
T5 = 5302370 
T6 = 5256763 
T7 = 3779166 
T8 = 6309599 
T9 = 6236041 
Total = 50542073 

Использования 10 Threadpool рабочих элементов

 
T0 = 23335890 
T1 = 20998989 
T2 = 22920781 
T3 = 9802624 
T4 = 0 
T5 = 0 
T6 = 0 
T7 = 0 
T8 = 0 
T9 = 0 
Total = 77058284 

Обратите внимание, что только 4 нити элементы бассейна работы из 10 когда-либо фактически исполненных во время 1-секундного среза! Это на четырехъядерном процессоре, так что это был один поток на ядро.Другие задачи, выполненные после первых четырех завершенных, и поскольку уже выделенные 1 секунда истекли, они не увеличивали свои счетчики.

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

Использование пользовательской реализации ThreadPool из статьи

 
T0 = 7175934 
T1 = 6983639 
T2 = 5306292 
T3 = 5078502 
T4 = 3279956 
T5 = 8116320 
T6 = 3262403 
T7 = 7678457 
T8 = 8946761 
T9 = 8500619 
Total = 64328883 
+1

Что вы пропустили из своих результатов, так это то, что версия ThreadPool выполнена значительно лучше, чем ваша версия, отличная от threadpool, примерно на 50%! В статье говорилось, что использование ThreadPool было значительно медленнее, но это уже не так. Как и все в программировании, хотя это сводится к «это зависит». Если ваши задачи не требуют немедленного запуска, то вы можете использовать ThreadPool, и они быстрее закончатся из-за меньшего переключения контекста, иначе вы можете управлять им самостоятельно. –

+0

@Matthew: Да, я согласен с тем, что ThreadPool подсчитал больше, но я не согласен с этой причиной. Причина, по которой ThreadPool подсчитывает больше, состоит в том, что четыре потока ThreadPool уже существуют, тогда как при создании новых потоков вручную требуется значительное количество времени для начала потока. Поэтому я бы отменил ваше заключение: если ваши задачи не должны выполняться немедленно, используйте новый Thread; если вам нужно выполнить немедленно, используйте ThreadPool (и не зацикливайте его на длинные задачи). – Sander