Это, конечно, возможно, но это невероятно сложная задача.Это было центральным направлением исследований компиляторов в течение нескольких десятилетий.Основная проблема заключается в том, что мы не можем создать инструмент, который может найти лучший раздел на потоки для кода Java (это эквивалентно проблеме остановки).
Вместо этого нам нужно ослабить нашу цель из лучшего раздела в некоторый раздел кода.Это все еще очень сложно в целом.Итак, нам нужно найти способы упростить проблему, один из них - забыть об общем коде и начать смотреть на конкретные типы программ.Если у вас есть простой поток управления (постоянные ограниченные циклы for, ограниченное ветвление ....), то вы можете сделать гораздо больше.
Еще одно упрощение - сокращение количества параллельных блоков, которые вы пытаетесьчтобы быть занятым.Если вы соедините оба эти упрощения вместе, вы получите современный уровень автоматической векторизации (особый тип распараллеливания, который используется для генерации кода стиля MMX / SSE).Достижение этой стадии заняло десятилетия, но если вы посмотрите на компиляторы, такие как Intel, то производительность начинает становиться довольно хорошей.
Если вы переходите от векторных инструкций внутри одного потока к нескольким потокам в процессе, то у вас естьогромное увеличение задержки перемещения данных между различными точками в коде.Это означает, что ваше распараллеливание должно быть намного лучше, чтобы выиграть от коммуникационных накладных расходов.В настоящее время это очень актуальная тема в исследованиях, но нет доступных автоматических инструментов для пользователей.Если вы можете написать тот, который работает, это будет очень интересно многим людям.
Для вашего конкретного примера, если вы предполагаете, что rand () является параллельной версией, поэтому вы можете вызывать ее независимо от разных потоков, тогда это вполнеЛегко видеть, что код можно разделить на две части.Компилятор будет преобразовывать просто необходим анализ зависимостей, чтобы увидеть, что ни один цикл не использует данные и не влияет на другой.Таким образом, порядок между ними в коде пользовательского уровня является ложной зависимостью, которая может разделяться (т.е. помещать каждую в отдельный поток).
Но на самом деле вы не хотите распараллеливать код.Похоже, что каждая итерация цикла зависит от предыдущей, поскольку sum1 + = rand (100) совпадает с sum1 = sum1 + rand (100), где sum1 в правой части - это значение предыдущей итерации.Однако единственной задействованной операцией является сложение, которое является ассоциативным, поэтому мы переписываем сумму многими различными способами.
sum1 = (((rand_0 + rand_1) + rand_2) + rand_3) ....
sum1 = (rand_0 + rand_1) + (rand_2 + rand_3) ...
Преимущество второго состоит в том, что каждое сложение в скобках может быть вычислено параллельно для всехдругие.Как только у вас будет 50 результатов, их можно объединить в еще 25 дополнений и т. Д. Таким образом, вы проделаете больше работы: 50 + 25 + 13 + 7 + 4 + 2 + 1 = 102 дополнения против 100 в оригинале, но естьвсего 7 последовательных шагов, поэтому помимо параллельного разветвления / соединения и накладных расходов на связь он выполняется в 14 раз быстрее.Это дерево дополнений называется операцией сбора в параллельных архитектурах и, как правило, является дорогостоящей частью вычислений.
На очень параллельной архитектуре, такой как графический процессор, приведенное выше описание будет лучшим способом распараллеливания кода.Если вы используете потоки внутри процесса, это может привести к перегрузкам.
Подводя итог : это невозможно сделать идеально, это очень трудно сделать хорошо, есть много активных исследований, чтобы выяснить, сколько мы можем сделать.