Рассмотрим теперь возможность построения параллельного алгоритма, который выполнял бы только те вычислительные действия, что и последовательный метод (может быть только в несколько ином порядке) и, как результат, обеспечивал бы получение точно таких же решений исходной вычислительной задачи. Как уже было отмечено выше, в последовательном алгоритме каждое очередное k-е приближение значения ui,j вычисляется по последнему k-му приближению значений ui-1,j и ui,j-1 и предпоследнему (k-1)-му приближению значений ui+1,j и ui,j+1. Таким образом, при требовании совпадения результатов вычислений последовательных и параллельных вычислительных схем в начале каждой итерации метода только одно значение u11 может быть пересчитано (возможности для распараллеливания нет). Но далее после пересчета u11 вычисления могут выполняться уже в двух узлах сетки u12 и u21 (в этих узлах выполняются условия последовательной схемы), затем после пересчета узлов u12 и u21 — в узлах u13, u22 и u31 и т.д. Обобщая сказанное, можно увидеть, что выполнение итерации метода сеток можно разбить на последовательность шагов, на каждом из которых к вычислениям окажутся подготовленными узлы вспомогательной диагонали сетки с номером, определяемым номером этапа – см. рис. 11.8. Получаемая в результате вычислительная схема получила наименование волны или фронта вычислений, а алгоритмы, построенные на ее основе, — методов волновой обработки данных (wavefront или hyperplane methods). Следует отметить, что в нашем случае размер волны (степень возможного параллелизма) динамически изменяется в ходе вычислений – волна нарастает до своего пика, а затем затухает при приближении к правому нижнему узлу сетки.
Рис. 11.8. Движение фронта волны вычислений
Возможная схема параллельного метода, основанного на эффекте волны вычислений, может быть представлена в следующей форме.
Алгоритм 11.5. Параллельный алгоритм, реализующий волновую схему вычислений
Пример 11.5.
(html, txt)
При разработке алгоритма, реализующего волновую схему вычислений, оценку погрешности решения можно осуществлять для каждой строки в отдельности (массив значений dm).
Этот массив является общим для всех выполняемых потоков, однако синхронизации доступа к элементам не требуется, так как потоки используют всегда разные элементы массива (фронт волны вычислений содержит только по одному узлу строк сетки).
После обработки всех элементов волны в составе массива dm находится максимальная погрешность выполненной итерации вычислений. Однако именно эта последняя часть расчетов может оказаться наиболее неэффективной из-за высоких дополнительных затрат на синхронизацию. Улучшение ситуации, как и ранее, может быть достигнуто за счет увеличения размера последовательных участков и сокращения, тем самым, количества необходимых взаимодействий параллельных участков вычислений. Возможный вариант реализации такого подхода может состоять в следующем:
chunk = 200; // размер последовательного участка #pragma omp parallel for shared(n,dm,dmax) private(i,d) for ( i=1; i<nx+1; i+=chunk ) { d = 0; for ( j=i; j<i+chunk; j++ ) if ( d < dm[j] ) d = dm[j]; omp_set_lock(dmax_lock); if ( dmax < d ) dmax = d; omp_unset_lock(dmax_lock); } // конец параллельной области
100 | 210 | 0,06 | 210 | 0,30 | 0,21 | 210 | 0,16 | 0,40 |
200 | 273 | 0,34 | 273 | 0,86 | 0,40 | 273 | 0,59 | 0,58 |
300 | 0,88 | 305 | 1,63 | 0,54 | 305 | 1,53 | 0,57 | |
400 | 318 | 3,78 | 318 | 2,50 | 1,51 | 318 | 2,36 | 1,60 |
500 | 343 | 6,00 | 343 | 3,53 | 1,70 | 343 | 4,03 | 1,49 |
600 | 336 | 8,81 | 336 | 5,20 | 1,69 | 336 | 5,34 | 1,65 |
700 | 344 | 12,11 | 344 | 8,13 | 1,49 | 344 | 10,00 | 1,21 |
800 | 343 | 16,41 | 343 | 12,08 | 1,36 | 343 | 12,64 | 1,30 |
900 | 358 | 20,61 | 358 | 14,98 | 1,38 | 358 | 15,59 | 1,32 |
1000 | 351 | 25,59 | 351 | 18,27 | 1,40 | 351 | 19,30 | 1,33 |
2000 | 367 | 106,75 | 367 | 69,08 | 1,55 | 367 | 65,72 | 1,62 |
3000 | 370 | 243,00 | 370 | 149,36 | 1,63 | 370 | 140,89 | 1,72 |