| Многопоточность: истинная скорость (09.06.2026). |
|
| 2026 - Июнь | |
| 09.06.2026 13:37 | |
Обобщая все материалы по многопоточности: первый, второй, третий, четвёртый, пятый, шестой. Результаты: - переписана однопоточная программа расчёта простых чисел на Visual Basic v.6.0, став многопоточной на Borland C++ Builder v.6.0 (размещена вместе с исходниками); - переписана повторно - добавлены диагностические механизмы и понимание, почему прирост скорости только 3 раза, а не 11 (исходники были заменены); - и вот сейчас, любопытство перевесило лень: а что будет, если убрать тормозящие нюансы - и вывести эту программу на загрузку процессора до усрачки (исходники потом будут добавлены)? Переписана ещё раз. ...теперь понимаю, почему ушёл из программирования. ...ушёл, бл.., как же...
Причины, тормозящие прирост скорости, - банальные и удобные (подача чисел на анализ порциями, с ожиданием завершения работы всех потоков, направленных на порцию): - родительский поток тупо не успевал раздавать задачи дочерним - в случае, если потоков много, и частота их мала; - один поток тупо тормозил все остальные, давно выполнившие свою задачу, - в случае работы с квадриллионными числами; - недостатки компенсировались автоматической сортировкой полученных простых чисел как в пределах порции - так и всего массива полученных простых чисел. Сортировка Шелла, самая быстрая, обрабатывает 16млн чисел за ~10мин - изменение данной парадигмы работы с потоками сулило большие проблемы при работе с большим результатным массивом чисел. Особенный риск был при поиске простых чисел, начиная с 2: прирост скорости обнаружения чисел мог обернуться замедлением при сортировке. Переделка парадигмы работы с числами: - потоки создаются разом и уничтожаются только по окончании работы с числами. Текущее обрабатываемое число, текущая позиция массива результатов и сам массив результатов - вынесены в глобальные и стали волатильными; - в функции потока стало несколько входов в критическую секцию вместо одной. Результаты: - скорость нахождения простых чисел на i5-10400 в Windows 10 - улетела в стратосферу. Первые 16777215 простых чисел находились за 2:57 вместо 57:52 (особенно контрастно на фоне только что прочтённой книги по квантовой механике, ещё раз подтвердившей нефатальность мира). Это невозможно объяснить тем, что ЦП разогнался: у Intel с этим проблемы жульничества: разгоняется только первое ядро, которое родительское и в расчётах не участвует; - дело не только в том, что ЦП теперь загружен на 100%. Родительский поток не просто перестал тормозить дочерние - он сам, как паразитный, стал выглядеть на их фоне гораздо менее жрущим ресурсы (код перенёсся в функцию потоков). Если ранее считалось, что он жрал ~23% при общей загрузке 50% (максимум, на который удавалось выходить) - теперь приходит понимание, что он жрал гораздо больше. Оставшиеся 27% размазывались по 11 дочерним потокам у i5-10400 (29% загрузки каждого) и ~4% по 23 у E5-2696 V2 (4.2% загрузки каждого). Плюс простой потоков, пока вся порция данных не обработается, - оказался недооценённым. А теперь, дочерние потоки вышли на максимум скорости и почти отсутствие задержек (только вход в критическую секцию) - вот и прирост получился в 19.6 раза; - и загадка остаётся: как может быть прирост в 60 раз относительно однопоточного варианта, когда однопоточное грузит поток на 100%, а в ЦП логических процессоров всего 12; - значит, у Borland C++ Builder v.6.0 нет проблем с работой с потоками, в контексте скорости, - остаются только нерабочими WaitFor, Suspend, Suspended; - потребление памяти - не пострадало: она выделяется только в момент принудительного зануления массива результатов перед началом работы - так и осталось на уровне ~130МБ. Расплата (хаос скорости работы потоков является хаотичным - двойной уровень вложенности, а не масло масляное); - мало того, что частота потоков пляшет (аналоговая ТТХ ЦП: логические процессоры), так и сама ОС ещё перекидывает нагрузку с одного логического процессора на другой - даже если ЦП загружен на 100%; - при загруженности 11 логических процессоров из 12 (12-й - родительский, крутящий ProcessMessages() и отображающий индикатор работы), - открытый заранее диспетчер задач просрался только через 50с (показав 100% загрузки ЦП), мышь иногда подвешивалась; - скорость индикации новой "порции" простых чисел менялась. То мчится как сумасшедшая последовательно по 1000шт. То пропадёт, подумает - хрясь, сразу на миллион больше показывает; - к граничной величине массива 16777216 чисел (максимум для Excel 2002) нужно прибавить 128 (максимальное число логических процессоров одного ЦП). Несмотря на то, что числа получаются более-менее отсортированными, - возникает ситуация: заказал 1000 чисел - приходит 1000-1005. И нельзя от крайних отказаться: если число 7933 закончится обрабатываться раньше 7919 - 7933 в результат попадёт, а 7919 - нет; - отображение состояния работы потоков - начало глючить: часть потоков не показывает, что работа была завершена, - и остается гореть зелёным. Вообще, данный функционал потерял свой смысл: даже в ущербном диспетчере задач видно, что при расчётах - загружено буквально всё или буквально ничего. В Excel 2002 сортировка полученных чисел не удалась: есть только её иллюзия - данные остаются на своих местах. Так сколько же времени отнимет сортировка именно в этом проекте? А вот хрен, а не реализация: сортировке Шелла (которую ещё и с VB6 переписывать) теперь противостоит поразрядная сортировка. Которая представлена на C++ в разных вариантах - но люди отмечают, что все они являются не оптимизированным по скорости говнокодом, - т.е. с кодом надо повторить то же вылизывание, что и в VB6 для Шелла, - проще застрелиться. |
|
| Обновлено ( 09.06.2026 16:33 ) |