Взрыв памяти потоков Java - PullRequest
2 голосов
/ 15 июля 2010

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

Я реализую быструю сортировку в Java JDK 7 (Fork Join API) для сортировки списка объектов (100 КБ).

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

Я просто добавил код, чтобы использовать его на многоядерных процессорах (путем расширения класса RecursiveAction), а затем использование памяти резко возросло, пока не достигло своих пределов. Выполняя некоторое профилирование, я наблюдаю высокую скорость создания потоков и думаю, что это ожидаемо. Но является ли Java-поток сам по себе намного более требовательным к памяти или я что-то здесь упускаю?

Для быстрой сортировки требуется много потоков, но не больше, чем у обычных объектов.

Должен ли я прекратить создание потоков RecursiveAction при достижении порогового значения, а затем просто переключиться на последовательный фрагмент кода (больше потоков не будет)?

Большое спасибо.

Ответы [ 4 ]

3 голосов
/ 15 июля 2010

Потоки Java обычно по умолчанию занимают 256 КБ / 512 КБ (углубляясь в ОС, версии JDK ...) одного стекового пространства.

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

0 голосов
/ 15 июля 2010

Я изменил свой код, и пока у меня есть лучшие результаты. Я вызываю основную задачу Thread в ForkJoinPool, в Threads я не создаю больше потоков, если в ForkJoinPool гораздо больше активных потоков, чем доступных ядер.

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

Я собираюсь узнать больше.

Спасибо всем!

0 голосов
/ 15 июля 2010

Как правило, для вычислений с привязкой к ЦП, когда количество потоков превышает количество доступных ядер, добавление дополнительных потоков не ускорит процесс. Фактически, это, вероятно, замедлит вас из-за накладных расходов на создание потоков, ресурсов, связанных каждым потоком (например, стеки потоков), и стоимости синхронизации.

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

0 голосов
/ 15 июля 2010

Да, переход на последовательный код - это хорошая идея, когда единица работы находится в районе ок.10000-100000 операций.Это просто правило.Так что для быстрой сортировки я бы выбрал последовательное выполнение, когда размер сортируемого файла меньше, чем, скажем, 10-20 000 элементов, в зависимости от сложности операции сравнения.

Каков размер ForkJoinPool- обычно он настроен на создание того же числа потоков, что и процессоры, поэтому вы не должны видеть слишком много потоков.Если вы вручную установили высокий уровень параллелизма (скажем, в сотнях или тысячах), вы увидите, что интенсивно (виртуально) используется память, поскольку каждый поток выделяет пространство для стека (256 КБ по умолчанию для 32-разрядных окон и Linux.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...