2012-03-26 2 views
5

Использование: C++ (MinGW), Qt4.7.4, Vista (OS), intel core2vProCPU Cores не утилизируется должным образом с использованием объектов QThread

мне нужно обрабатывать 2 огромных файлов точно так же. Поэтому я хотел бы назвать процедуру обработки из двух отдельных потоков для двух отдельных файлов. Ничья GUI не делает ничего тяжелого; просто отображает метку и запускает цикл событий для проверки испускания условий завершения потока и соответственно выходит из основного приложения. Я ожидал, что это будет использовать два ядра (intel core2) несколько одинаково, но, наоборот, я вижу из диспетчера задач, что один из ядер сильно используется, а другой нет (хотя не каждый раз, когда я запускаю код); также время, затрачиваемое на обработку 2-х файлов, намного больше, чем время, затрачиваемое на обработку одного файла (я думал, что он должен быть равен или немного больше, но это почти равно обработке двух файлов один за другим в безпоточной заявление). Могу ли я каким-то образом заставить потоки использовать ядра, которые я указываю?

QThread* ptrThread1=new QThread; 
QThread* ptrThread2=new QThread; 
ProcessTimeConsuming* ptrPTC1=new ProcessTimeConsuming(); 
ProcessTimeConsuming* ptrPTC2=new ProcessTimeConsuming(); 

ptrPTC1->moveToThread(ptrThread1); 
ptrPTC2->moveToThread(ptrThread2); 

//make connections to specify what to do when processing ends, threads terminate etc 
//display some label to give an idea that the code is in execution 

ptrThread1->start(); 
ptrThread2->start(); //i want this thread to be executed in the core other than the one used above 

ptrQApplication->exec(); //GUI event loop for label display and signal-slot monitoring 
+7

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

+0

Являются ли файлы примерно одинакового размера? – Tudor

+0

@PeteKirkham: просто есть 1 HDD – ustulation

ответ

16

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

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

+0

я вижу .. вы можете сказать мне, как заставить поток по ядру выбора? – ustulation

+0

@ustust: 'qthread' не предоставляет такой API сродства. Кроме того, вам почти никогда не нужно устанавливать сродство к отдельным ядрам, потому что планировщик будет как можно лучше устанавливать сопоставление потоков к процессору. В любом случае, если вам действительно нужно, см. Этот пост об использовании вызовов в библиотеке pthread для достижения этой цели: http://qt-project.org/faq/answer/setting_thread_processor_affinity_in_linux – Tudor

+0

спасибо .. я думаю, мне нужно придерживаться последовательной обработки потому что размер файла запрещен для чтения в ОЗУ, за которым следует обработка. В отдельной заметке я никогда не использовал 'boost threads'. Не могли бы вы дать мне подсказку о том, имеет ли она эту функцию (core Affinity API), чтобы i вникать в него, когда мне это нужно? – ustulation

1

Я думал, что мои эмпирические данные могут быть полезными для обсуждения. У меня есть каталог с файлами 980 txt, которые я бы хотел прочитать. В рамках Qt/C++ и работая на четырехъядерном ядре Intel i5, я создал приложение GUI и добавил работника класса для чтения файла с учетом его пути. Я толкнул работника в поток, а затем повторил добавление дополнительного потока в каждом прогоне. Я провел примерно 13 минут с 1 нитью, 9 минут с 2 и 8 минут с 3. Итак, в моем случае была какая-то польза, но она быстро ухудшилась.

+0

Любая система, которая позволяет одиночному потоку исчерпать емкость чтения/записи, будет нестабильной или, по крайней мере, не отвечает на пользователя. Если вы не уйдете с пути, потоки эффективно блокируют свои ИО. Что вы делали, так это требовать, чтобы ваша программа имела более высокий приоритет, запустив два потока. – Mikhail

+0

Все зависит от размера файлов. Как правило, на механических жестких дисках, если вы хотите, чтобы накладные расходы были менее 10%, вы должны прочитать пару мегабайт за раз. Поэтому, если файлы меньше, скажем, 2 Мбайта, вы читаете их целиком. Если они больше, то вы можете объединять файлы между файлами, чтобы больше загружать потоки вычислений. –

2

С механическими жесткими дисками вам необходимо явно контролировать соотношение времени, затраченного на последовательное чтение, и время, затрачиваемое на поиск. Канонический способ сделать это с n + m объектов, работающих на m+min(n, QThread::idealThreadCount()) потоков. Здесь m - количество жестких дисков, на которых находятся файлы, и n - это количество файлов.

  • Каждый из м объектов читает файлы из данного жесткого диска в циклическому. Каждое чтение должно быть достаточно большим. На современных жестких дисках давайте выделим пропускную способность в 70 мегабайт/с (вы можете сравнить реальную стоимость), 5 мс для поиска. Чтобы тратить не более 10% полосы пропускания, вы получаете только 100 мс или 100 мс/(5 мс/поиск) = 20 запросов в секунду. Таким образом, перед чтением из следующего файла вы должны прочитать не менее 70 Мбайт/(20seeks + 1) = 3,3 мегабайта из каждого файла. Этот поток заполняет буфер данными файла, а затем буфер передает соответствующий объект вычисления, который прикреплен к другой стороне буфера. Когда буфер занят, вы просто пропускаете чтение из заданного файла, пока буфер снова не станет доступен.

  • Другие объекты n Объекты являются вычислительными объектами, они выполняют вычисление по сигналу из буфера, который указывает, что буфер заполнен. Как только данные буфера больше не нужны, буфер «перезагружается», чтобы считыватель файлов мог его пополнить.

Все объекты-читатели нуждаются в собственных потоках. Объекты вычислений могут быть распределены между своими потоками циклически, так что все потоки имеют в пределах +1, -0 объектов друг от друга.