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

Почему многопоточность в С# не достигает 100% CPU?

Я работаю над программой, которая обрабатывает многие запросы, ни одна из которых не достигает более 50% CPU (в настоящее время я работаю над двухъядерным). Поэтому я создал поток для каждого запроса, весь процесс выполняется быстрее. Обработка 9 запросов, один поток длится 02min08s, в то время как три потока работают одновременно с временем, уменьшенным до 01min37s, но он не использует 100% CPU, всего около 50%.

Как я могу позволить моей программе использовать возможности полных процессоров?

ИЗМЕНИТЬ Приложение не ограничено IO или памятью, они находятся на разумных уровнях все время.

Я думаю, что это имеет какое-то отношение к "двойному ядру".

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

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

EDIT2

Очень вероятно, что метод STA COM - моя проблема, я связался с владельцами компонентов, чтобы решить эту проблему.

4b9b3361

Ответ 1

У вас есть значительная блокировка в вашем приложении? Если потоки ждут друг друга много, что может легко объяснить это.

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

EDIT: Хорошо, учитывая приведенные ниже комментарии, я думаю, что мы что-то делаем:

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

Является ли метод COM запущенным в STA каким-либо образом? Если это так, он будет использовать только один поток, сериализуя вызовы. Я сильно подозреваю, что ключ к ней. Это похоже на блокировку этого вызова (не совсем то же, по общему признанию).

Ответ 2

Проблема заключается в COM-объекте.

Большинство COM-объектов работают в контексте "однопоточной квартиры". (Вы, возможно, время от времени видели аннотацию [STAThread] по основному методу приложения .NET?)

Эффективно это означает, что все отправления к этому объекту обрабатываются одним потоком. Бросать больше ядер на проблему просто дает вам больше ресурсов, которые могут сидеть и ждать или делать другие вещи в .NET.

Возможно, вы захотите взглянуть на эту статью от Джо Даффи (руководителя параллельного .NET в Microsoft) по этой теме.

http://www.bluebytesoftware.com/blog/PermaLink,guid,8c2fed10-75b2-416b-aabc-c18ce8fe2ed4.aspx

На практике, если вам нужно сделать кучу вещей против одного COM-объекта, подобного этому, вы будете закрыты, так как .NET будет просто сериализовать шаблоны доступа за вашей спиной. Если вы можете создать несколько COM-объектов и использовать их, вы можете решить проблему, потому что каждый из них может быть создан и доступен из отдельного потока STA. Это будет работать до тех пор, пока вы не нажмете около 100 потоков STA, тогда все будет неудобно. Подробнее см. В статье.

Ответ 3

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

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

Ответ 4

Это зависит от вашей программы - работа, выполняемая вашими параллельными запросами, может быть связана с IO-ограничением скорости (например, вашего жесткого диска), а не с привязкой к процессору, когда вы увидите, что ваш процессор достигает 100%,

После редактирования это звучит, как COM STA объекты могут быть виновником.

Влияют ли все потоки на один и тот же экземпляр объекта COM? Можно ли сделать потоки STA для рабочих потоков и создать отдельный экземпляр COM-объекта для каждого потока. Таким образом, можно избежать узкого места STA.

Чтобы узнать, является ли COM-класс STA:

class Test
{
  static void Main() //This will be an MTA thread by default
  {
    var o = new COMObjectClass();
    // Did a new thread pop into existence when that line was executed?
    // If so, .NET created an STA thread for it to live in.
  }
}

Ответ 5

Я думаю, что у меня была аналогичная проблема. Я создавал несколько потоков в С#, которые запускали С++-код через COM-интерфейс. Мой двухъядерный процессор никогда не достигал 100%.

Прочитав этот пост, я почти сдался. Затем я попытался позвонить SetApartmentState (ApartmentState.STA) в мои темы.

После того, как это было изменено, CPU был отключен.

Ответ 6

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

Ответ 7

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

Test: Попробуйте использовать только 2 потока и задайте ему близость каждого потока для каждого ядра. Затем откройте диспетчер задач и посмотрите загрузку обоих ядер.

Ответ 8

Это не ответ на самом деле, но вы проверили perfmon, чтобы узнать, какие ресурсы он использует, и запустите профайлеры кода, чтобы увидеть, где он проводит время?

Как вы определили, что IO или другие ресурсы не ЦП не являются узким местом?

Можете ли вы дать краткое описание того, что делают потоки?

Ответ 9

если ваш процесс запущен на процессоре 0 и там нерестится, максимум, который он когда-либо достигнет, составляет 50%. Посмотрите, есть ли потоки, запущенные на обоих ядрах или только на одном. Я бы рискнул предположить, что вы изолированы от одного ядра или что один из ваших зависимых ресурсов заблокирован на одном ядре. Если он достигнет ровно 50%, то одно ядро, скорее всего, станет вашим узким местом.

Ответ 10

Итак, вы решили проблему использования одного COM-объекта и теперь имеете проблему с IO.

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

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

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

Ответ 11

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

Какую операционную систему вы используете?

Я, кажется, смутно вспоминаю, что в старых версиях окон (например, ранних XP и 2000-х годах) загрузка процессора рассматривалась из общей суммы двух процессоров, поэтому один поток не смог преодолеть 50%, если только это не было процесс простоя.

Ответ 12

Еще одно замечание: вы пытались запустить свой код не из Visual Studio (независимо от настроек выпуска/отладки)?

Ответ 13

Проблема заключается в COM-объекте. Это STA, и я не могу либо иметь два экземпляра, работающих одновременно в одном и том же процессе. Когда я создаю экземпляр для класса COM, другой становится непригодным.

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

Спасибо вам всем;)