Подтвердить что ты не робот

Запуск нескольких задач из службы WCF

Мне нужно оптимизировать службу WCF... это довольно сложная вещь. Моя проблема на этот раз связана с задачами (Task Parallel Library,.NET 4.0). Случается, что я запускаю несколько задач при вызове службы (используя Task.Factory.StartNew), а затем дождался их завершения:

Task.WaitAll(task1, task2, task3, task4, task5, task6);

Хорошо... то, что я вижу и не люблю, - это то, что при первом вызове (иногда первые 2-3 звонка, если они делаются быстро один за другим), конечная задача начинается намного позже других ( Я смотрю на случай, когда он начался через 0,5 секунды после остальных). Я попробовал позвонить

ThreadPool.SetMinThreads(12*Environment.ProcessorCount, 20);

в начале моей службы, но, похоже, это не помогает.

Все задачи связаны с базой данных: я читаю из нескольких баз данных и занимает как можно меньше времени.

Любая идея, почему последняя задача занимает так много времени? Что-то я могу с этим поделать?

В качестве альтернативы, следует ли использовать пул потоков напрямую? Как это бывает, в одном случае, на который я смотрю, одна задача уже закончилась до того, как начался последний - я бы сэкономил 0,2 секунды, если бы повторно использовал этот поток вместо того, чтобы ждать создания нового. Однако я не могу быть уверен, что эта задача всегда будет заканчиваться так быстро, поэтому я не могу поставить оба запроса в одну и ту же задачу.

[Изменить] ОС - это Windows Server 2003, поэтому не должно быть ограничений на соединение. Кроме того, он размещен в IIS - я не знаю, должен ли я создавать обычные потоки или использовать пул потоков - что является предпочтительной версией?

[Edit] Я также попытался использовать Task.Factory.StartNew(action, TaskCreationOptions.LongRunning); - это не помогает, последняя задача по-прежнему начинается намного позже (примерно через полсекунды), чем остальные.

[Изменить] MSDN 1 говорит:

Пул потоков имеет встроенную задержку (полсекунды в .NET Framework версия 2.0) перед запуском нового простоя потоки. Если ваша заявка периодически запускает множество задач в короткое время, небольшое увеличение количество простаивающих потоков может значительное увеличение пропускной способности. Установка количества простоя высокая потребляет системные ресурсы без необходимости.

Однако, как я уже сказал, я уже звоню в SetMinThreads, и это не помогает.

4b9b3361

Ответ 1

У меня были проблемы с задержками при запуске потоков при использовании объекта задачи (.Net 4.0) Task. Поэтому для критически важных вещей я теперь использую выделенные потоки (... опять же, поскольку это то, что я делал до .Net 4.0.)

Цель пула потоков состоит в том, чтобы избежать оперативной стоимости системы запуска и остановки потоков. Нити просто используются повторно. Это обычная модель, найденная, например, для интернет-серверов. Преимущество состоит в том, что они могут быстрее реагировать.

Я написал много приложений, где я реализую свой собственный threadpool, когда выделенные потоки собирают задачи из очереди задач. Обратите внимание, однако, что это наиболее часто требуется блокировка, которая может вызвать задержки/узкие места. Это зависит от вашего дизайна; это небольшие задачи, тогда было бы много блокировки, и было бы быстрее торговать некоторым процессором за меньшую блокировку: http://www.boyet.com/Articles/LockfreeStack.html

SmartThreadPool является заменой/расширением пула потоков .Net. Как вы можете видеть в этой ссылке, у него есть хороший графический интерфейс для проведения некоторых тестов: http://www.codeproject.com/KB/threads/smartthreadpool.aspx

В конце концов, это зависит от того, что вам нужно, но для высокой производительности я рекомендую реализовать свой собственный пул потоков. Если вы испытываете много простоя на холостом ходу, может быть полезно увеличить количество потоков (за пределами рекомендуемого cpucount * 2). Это фактически то, как HyperThreading работает внутри CPU - используя "свободное время", делая операции для выполнения других операций.

Обратите внимание, что .Net имеет встроенный предел в 25 потоков для каждого процесса (т.е. для всех вызовов WCF, которые вы получаете одновременно). Это ограничение является независимым и переопределяет параметр ThreadPool. Он может быть увеличен, но требует некоторой магии: http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=201

Ответ 2

Следуя моему предыдущему вопросу (да, должно было быть Q против исходного сообщения - извинения):

Почему вы чувствуете, что создание 12 потоков для каждого ядра процессора на вашем компьютере каким-то образом ускорит вашу способность сервера создавать рабочие потоки? Все, что вы делаете, замедляет ваш сервер!

В соответствии с MSDN do

В соответствии с документами MSDN: "Вы можете использовать метод SetMinThreads для увеличения минимального количества потоков. Однако ненужное увеличение этих значений может привести к проблемам с производительностью. Если слишком много задач запускаются на одном уровне В большинстве случаев пул потоков будет лучше работать со своим собственным алгоритмом распределения потоков. Уменьшение минимального числа процессоров до меньшего, чем число процессоров, может также повредить производительность".

Такие проблемы обычно вызваны столкновением ограничений или конфликтов на общем ресурсе.

В вашем случае я предполагаю, что ваша последняя задача (-и) блокируется, пока они ждут подключения к серверу БД, доступного или для ответа БД. Помните - если ваш вызов запускает 5-6 других задач, тогда ваша машина должна будет создавать и открывать многочисленные соединения с БД и собирает удар по БД с потенциально большой работой. Если ваш сервер WCF и/или ваш сервер БД холодны, ваши первые несколько вызовов будут медленнее, пока не будут заполнены машины и т.д.

Вы пытались добавить небольшое отслеживание/ведение журнала с помощью секундомера вовремя, сколько времени требуется, чтобы ваши задачи подключались к серверу БД, а затем выполняли их операции?

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

Ответ 3

Когда вы вызываете Task.Factory.StartNew, он использует TaskScheduler для сопоставления этих задач с фактическими рабочими элементами.

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

Сказав, я подозреваю, что здесь есть что-то другое... Вы упомянули, что использование TaskCreationOptions.LongRunning демонстрирует то же поведение. Это говорит о том, что в игре есть еще один фактор, вызывающий эту половину задержки. Причина, по которой я подозреваю, связана с природой TaskCreationOptions.LongRunning - при использовании TaskScheduler по умолчанию (LongRunning - это подсказка, используемая классом TaskScheduler), запуск задачи с помощью TaskCreationOptions.LongRunning фактически создает совершенно новый (не -ThreadPool) для этой задачи. Если вы создаете 6 задач, все с TaskCreationOptions.LongRunning, демонстрирует одно и то же поведение, вы почти гарантировали, что проблема НЕ является TaskScheduler по умолчанию, так как это всегда будет разворачивать 6 потоков вручную.

Я бы рекомендовал запустить ваш код через профилировщик производительности и, возможно, Concurrency Visualizer в VS 2010. Это должно помочь вам точно определить, что вызывает задержку в полсекунды.

Ответ 4

Что такое ОС? Если вы не используете серверные версии окон, существует ограничение на соединение. Ваши многие потоки, вероятно, сериализуются из-за ограничения соединения.

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

Ответ 5

Эти статьи могут объяснить проблему, с которой вы сталкиваетесь: http://blogs.msdn.com/b/wenlong/archive/2010/02/11/why-are-wcf-responses-slow-and-setminthreads-does-not-work.aspx

http://blogs.msdn.com/b/wenlong/archive/2010/02/11/why-does-wcf-become-slow-after-being-idle-for-15-seconds.aspx

видя, что вы используете .Net 4, первая статья, вероятно, не применяется, но, как следует из второй статьи, ThreadPool завершает простоя через 15 секунд, что может объяснить проблему, с которой вы столкнулись, и предлагает простой (хотя и немного хакерское) решение обойти его.

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

Одна сторонняя библиотека, которую мы использовали некоторое время, может вам помочь - Smart Thread Pool. Вы по-прежнему получаете те же преимущества от использования библиотек задач, что вы можете получать возвращаемые значения из потоков и получать от них информацию об исключениях.

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

Вы можете найти много информации на странице codeplex, у меня также есть сообщение, в котором выделяются некоторые ключевые отличия: http://theburningmonk.com/2010/03/threading-introducing-smartthreadpool/

Как раз на стороне заметки, для задач, подобных тем, о которых вы упоминали, что может занять некоторое время, чтобы вернуться, вы, вероятно, не должны использовать threadpool. Он рекомендовал, чтобы мы избегали использования threadpool для любых задач блокировки, подобных этому, потому что он запускает threadpool, который используется всеми видами вещей классами Framework, такими как обработка событий таймера и т.д. И т.д. (Не говоря уже об обработке входящего WCF Запросы!). Я чувствую, что я спам здесь, но здесь часть информации, которую я собрал вокруг использования threadpool и некоторых полезных ссылок внизу:

http://theburningmonk.com/2010/03/threading-using-the-threadpool-vs-creating-your-own-threads/

ну, надеюсь, это поможет!