Здравствуйте, коллеги-программисты. Я уже задавал один вопрос , но, несмотря на действительно хорошие ответы, я не смог решить свою проблему. Затем я потратил время на рефакторинг своего кода таким образом, чтобы улучшить его потенциал распараллеливания (за счет меньшего количества пакетов вычислений с большим объемом вычислений каждый). Но все же у меня не может быть лучшей производительности, чем последовательная обработка.
Я подозреваю, что эта медленная параллельная обработка происходит из-за переключения контекста . А может это из-за «автоматической» синхронизации общих объектов. Я думаю, вы можете помочь мне понять, что происходит.
Позвольте мне изложить мой случай: я делаю программу для научных расчетов. Он не зависит от внешних факторов, только от входных значений, которые я ему даю в начале.
Размер этой проблемы можно измерить нс
(это имя, которое я использую). Его можно рассматривать как «разрешение» решения, это один из вводимых пользователем данных, обычно порядка 100.
Таким образом, у меня есть несколько массивов double в моем основном классе, например double ys [Ns] [N]
или phiS [Ns] [Nord] [N]
, где N и Nord - другие фиксированные величины программы.
В моей программе я должен вычислить несколько вещей для каждой из точек Ns
, и вот идет распараллеливание. Расчет каждой точки независим, поэтому я могу разделить их на разные потоки и надеяться, что это будет быстрее.
Итак, вместо цикла for (int i = 0; i
for (int i = start; i
start = 0
и end = Ns / 2
, другая с start = Ns / 2
и end = Ns
. Если я на четырехъядерном, вторая партия будет иметь от start = Ns / 4
до end = Ns / 2
и так далее (при условии точного разделения в каждом случае).
Каждая партия, как a Класс, реализующий Runnable, хранится в ArrayList
и передается в FixedThreadPool
с размером, равным количеству ядер. Он выполняет пакеты и ожидает их завершения, используя простую схему CountDown
.
Каждому из этих пакетов требуется доступ к данным в этих массивах из основного класса программы, но их доступ таков, что каждый пакет читает только с yS [start] []
до yS [end] []
и поэтому два пакета никогда не будут пытаться прочитать один и тот же элемент массива. Интересно, по-прежнему ли Java блокирует yS, даже если каждая партия не работает? t пытается получить доступ к тем же элементам, что и другие.
Мне также интересно, связана ли моя проблема с накладными расходами из-за переключения контекста, поскольку каждая партия должна иметь дело с тысячами дубликатов, и может ли способ построения программы повлиять на это.
Может быть, мне стоит найти способ передать каждой партии только те элементы массивов, которые имеют к ней отношение, но я бы не знал, как к этому подойти. Если бы были указатели, я мог бы иметь новые массивы только желаемых элементов с простыми операциями с указателями и без перераспределения чего-либо. Есть ли способ сделать это в Java?
Ну, наконец, просто упомяну: есть одна часть кода, которую нужно синхронизировать (она имеет дело с другими массивами), и она уже работает нормально. поскольку каждая партия должна иметь дело с тысячами дубликатов, и может ли способ построения программы повлиять на нее.
Может быть, мне стоит найти способ передать каждой партии только те элементы массивов, которые имеют к ней отношение, но я бы не знал, как к этому подойти. Если бы были указатели, я мог бы иметь новые массивы только желаемых элементов с простыми операциями с указателями и без перераспределения чего-либо. Есть ли способ сделать это в Java?
Ну, наконец, просто упомяну: есть одна часть кода, которую нужно синхронизировать (она имеет дело с другими массивами), и она уже работает нормально. поскольку каждая партия должна иметь дело с тысячами дубликатов, и может ли способ построения программы повлиять на нее.
Может быть, мне стоит найти способ передать каждой партии только те элементы массивов, которые имеют к ней отношение, но я бы не знал, как к этому подойти. Если бы были указатели, я мог бы иметь новые массивы только желаемых элементов с простыми операциями с указателями и без перераспределения чего-либо. Есть ли способ сделать это в Java?
Ну, наконец, просто упомяну: есть одна часть кода, которую нужно синхронизировать (она имеет дело с другими массивами), и она уже работает нормально. Я не знаю, как к этому подойти. Если бы были указатели, я мог бы иметь новые массивы только желаемых элементов с простыми операциями с указателями и без перераспределения чего-либо. Есть ли способ сделать это в Java?
Ну, наконец, просто упомяну: есть одна часть кода, которую нужно синхронизировать (она имеет дело с другими массивами), и она уже работает нормально. Я не знаю, как к этому подойти. Если бы были указатели, я мог бы иметь новые массивы только желаемых элементов с простыми операциями с указателями и без перераспределения чего-либо. Есть ли способ сделать это в Java?
Ну, наконец, просто упомяну: есть одна часть кода, которую нужно синхронизировать (она имеет дело с другими массивами), и она уже работает нормально. Обязанности по расчету, которые я описал выше, - не единственное, чем занимается моя программа. Они находятся внутри цикла, чередующегося с последовательными частями обработки, но действительно важны, как общее время выполнения.
Итак, подведем итог, вопрос: почему я не получаю выгоду от многопоточности, когда я ожидал?
Я только что запускал здесь пару раз простой последовательный и многопоточную программу и получил 14500 мс для последовательного порта и 15651 мс для многопоточности. Оба на одном Dual Core. Еще одно замечание: при последовательном запуске каждое вычисление (от 0 до нс) занимает от 1,1 до 4,5 мс. В двухпотоковом режиме каждый пакет (Ns / 2 точки) занимает от 0,5 до 3 мс; (измеряется сверху вниз в методе run (). Каждый раз при вычислении отличается своей числовой сходимостью)
Большое спасибо за внимание.