Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[209]

списка, поскольку меняются поля указателей. Если необходимо сохранить список, необходимо сделать копии полей указателей и производить действия с копиями.

30.1.2.Корректность

Цикл в строках 5-9 имеет следующий инвариант: для любого объекта г либо next[i] указывает на объект, находящийся в списке на расстоянии d[i], либо next[i] = nil и d[i] есть расстояние до конца списка.

Заметьте, что для правильной работы алгоритма необходима синхронизация: чтение всех указателей next[next[i]] (в строке 9) должно произойти до записи их новых значений.

Теперь покажем, что программа List-Rank не использует одновременного обращения к памяти (и поэтому может выполняться на EREW-машине). Ясно, что в строках 2-7, а также при записи в строках 8 и 9 не происходит одновременного обращения к одной ячейке, так как за каждый элемент списка отвечает свой процессор. Кроме того, переход по указателям сохраняет следующий инвариант: для любых двух различных объектов t и j либо next[i] ф next[j], либо next[i] = next[j] = nil. Действительно, вначале это условие выполнено; оно сохраняется при исполнении строки 9. Поэтому при чтении в строке 9 не происходит одновременного обращения к одной ячейке.

В строке 8 не происходит одновременного чтения благодаря синхронизации: мы считаем, что сначала все процессоры читают d[i], и лишь затем с?[пеж£[г]]. В результате при г = next[j] содержимое d[i] сначала прочитывается г-м процессором, а затем j-m. При такой синхронизации алгоритм может работать на EREW-машине.

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

30.1.3.Анализ

Пусть список L содержит га элементов. Покажем, что время работы алгоритма составляет О (lgra). Поскольку инициализация и каждое выполнение цикла while занимают время 0(1), достаточно показать, что цикл выполняется lgra раз. Это следует из того, что при каждом выполнении цикла значения d[i] для тех элементов г, для которых next[i] ф nil, увеличиваются вдвое.

Мы предполагаем, что проверка условия в строке 5 занимает время 0(1) (при использовании управляющей сети). В упражнении 30.1-8 предлагается реализовать эту проверку без такой сети, сохранив время работы программы О (lgra).


Кроме времени работы, для параллельных алгоритмов мы будем оценивать также общие затраты (work), то есть произведение времени работы на количество используемых процессоров. Эта величина оценивает сверху время работы (однопроцессорного) алгоритма, моделирующего работу PRAM путём последовательного моделирования работы всех процессоров.

Общие затраты на вычисление номеров в списке составляют О (га lgra). Поскольку однопроцессорный алгоритм работает за время О (га) (за один проход по списку можно вычислить расстояния элементов от начала списка, а также его длину), при выполнении алгоритма List-Rank процессоры выполняют в сумме в lg га раз больше действий, чем необходимо однопроцессорному алгоритму.

Говорят, что алгоритм А не менее эффективен по затратам, чем алгоритм В (A is work-efficient with respect to В), если общие затраты А превышают общие затраты В не более чем в константу раз. Алгоритм А называется эффективным по затратам (work-efficient), если он не менее эффективен, чем любой однопроцессорный алгоритм. (В этом случае он не менее эффективен, чем любой алгоритм, поскольку многопроцессорный алгоритм можно моделировать на одном процессоре, последовательно моделируя работу каждого процессора.) Рассмотренный выше алгоритм отыскания номера в списке не является эффективным по затратам, поскольку существует алгоритм с затратами О (га). Эффективный по затратам вероятностный алгоритм для этой задачи строится в разделе 30.4.

30.1.4. Параллельная обработка префиксов списка

Метод переходов по указателям применяется не только для определения порядковых номеров элементов списка. Как показано в разделе 29.2.2, обработка префиксов позволяет быстро складывать числа. Здесь будет показано, как использовать метод переходов по указателям для обработки префиксов. Алгоритм обрабатывает префиксы га-элементного списка на EREW-машине за время О (lgra).

Пусть <g> - ассоциативная бинарная операция. Задача обработки префиксов (prefix computation) состоит в следующем: по данной последовательности (х\, х2, , хп) построить последовательность (У1,У2, , Уп), Для которой г/1 = xt и

Ук = Ук-i <S> хк = xt <g) х2 <8> ... <8> хк

для к = 2, 3,... , га. Другими словами, ук есть «©-произведение» первых к элементов последовательности.

Мы будем считать, что элементы хг, , хп, подлежащие обработке, связаны в односторонний список. (Аналогичная задача для


массива рассматривается в упражнении 30-1.2). Заметим для начала, что задачу о номере в списке можно рассматривать как частный случай задачи о параллельной обработке префиксов. Действительно, пусть каждый элемент списка равен 1, а операция <g> - обычное сложение. Тогда ук = к, то есть мы вычислили расстояние до начала списка. Поэтому обработку префиксов можно использовать для решения задачи о номере в списке - нужно лишь сначала обратить список (что можно сделать за время 0(1)).

Вернёмся к задаче о параллельной обработке префиксов. Введём следующие обозначения:

= Xi <g) Xi+1 <g) ... <g) Xj

при 1 i j п. В частности, [к, к] = хк и

[i,k] = [i,j]®\j + l,k]

при l.i.j<k.n. Наша цель - вычислить ук = [1, к] для всех к = 1,... , п.

В программе через x[i] обозначается значение объекта г. (Напоминаем, г есть адрес в памяти, а также номер ответственного за эту ячейку процессора, и никак не связан с к - порядковым номером в списке!) Алгоритм вычисляет y[i] = ук = [1,к], где x[i] = хк есть к-ъ с начала элемент списка.

List-Prefix(L)

1for (для) каждого процессора г

2do y[i] <- x[i]

3while существует объект г, для которого next[i] ф nil

4do for (для) каждого процессора г

5do if next[i] ф nil

6then у[пеж£[г]] <- y[i] <8> у[гаеж[г]]

7next[i] <- next[next[i]]

Видно, что алгоритм похож на алгоритм определения порядковых номеров элементов. Отличаются лишь инициализация и изменение значений у (в предыдущем алгоритме d). В алгоритме List-Rank процессор г изменяет значение y[i], соответствующее своему объекту, тогда как в алгоритме List-Prefix г-й процессор изменяет «чужое» значение г/[пеж£[г]]. (Если бы мы обрабатывали не префиксы, а суффиксы, то этой разницы бы не было.) Как и алгоритм List-Rank, алгоритм List-Prefix поддерживает следующий инвариант: для любых двух различных объектов г и j либо next[i] ф next[j], либо next[i] = next[j] = nil. Поэтому не происходит одновременного обращения к памяти, так что алгоритм можно реализовать на EREW-машине.

На рис. 30.3 показано состояние списка перед каждым выполнением цикла while. Цикл имеет следующий инвариант: после £-го повторения цикла указатели охватывают 2* звеньев списка (или



[стр.Начало] [стр.1] [стр.2] [стр.3] [стр.4] [стр.5] [стр.6] [стр.7] [стр.8] [стр.9] [стр.10] [стр.11] [стр.12] [стр.13] [стр.14] [стр.15] [стр.16] [стр.17] [стр.18] [стр.19] [стр.20] [стр.21] [стр.22] [стр.23] [стр.24] [стр.25] [стр.26] [стр.27] [стр.28] [стр.29] [стр.30] [стр.31] [стр.32] [стр.33] [стр.34] [стр.35] [стр.36] [стр.37] [стр.38] [стр.39] [стр.40] [стр.41] [стр.42] [стр.43] [стр.44] [стр.45] [стр.46] [стр.47] [стр.48] [стр.49] [стр.50] [стр.51] [стр.52] [стр.53] [стр.54] [стр.55] [стр.56] [стр.57] [стр.58] [стр.59] [стр.60] [стр.61] [стр.62] [стр.63] [стр.64] [стр.65] [стр.66] [стр.67] [стр.68] [стр.69] [стр.70] [стр.71] [стр.72] [стр.73] [стр.74] [стр.75] [стр.76] [стр.77] [стр.78] [стр.79] [стр.80] [стр.81] [стр.82] [стр.83] [стр.84] [стр.85] [стр.86] [стр.87] [стр.88] [стр.89] [стр.90] [стр.91] [стр.92] [стр.93] [стр.94] [стр.95] [стр.96] [стр.97] [стр.98] [стр.99] [стр.100] [стр.101] [стр.102] [стр.103] [стр.104] [стр.105] [стр.106] [стр.107] [стр.108] [стр.109] [стр.110] [стр.111] [стр.112] [стр.113] [стр.114] [стр.115] [стр.116] [стр.117] [стр.118] [стр.119] [стр.120] [стр.121] [стр.122] [стр.123] [стр.124] [стр.125] [стр.126] [стр.127] [стр.128] [стр.129] [стр.130] [стр.131] [стр.132] [стр.133] [стр.134] [стр.135] [стр.136] [стр.137] [стр.138] [стр.139] [стр.140] [стр.141] [стр.142] [стр.143] [стр.144] [стр.145] [стр.146] [стр.147] [стр.148] [стр.149] [стр.150] [стр.151] [стр.152] [стр.153] [стр.154] [стр.155] [стр.156] [стр.157] [стр.158] [стр.159] [стр.160] [стр.161] [стр.162] [стр.163] [стр.164] [стр.165] [стр.166] [стр.167] [стр.168] [стр.169] [стр.170] [стр.171] [стр.172] [стр.173] [стр.174] [стр.175] [стр.176] [стр.177] [стр.178] [стр.179] [стр.180] [стр.181] [стр.182] [стр.183] [стр.184] [стр.185] [стр.186] [стр.187] [стр.188] [стр.189] [стр.190] [стр.191] [стр.192] [стр.193] [стр.194] [стр.195] [стр.196] [стр.197] [стр.198] [стр.199] [стр.200] [стр.201] [стр.202] [стр.203] [стр.204] [стр.205] [стр.206] [стр.207] [стр.208] [стр.209] [стр.210] [стр.211] [стр.212] [стр.213] [стр.214] [стр.215] [стр.216] [стр.217] [стр.218] [стр.219] [стр.220] [стр.221] [стр.222] [стр.223] [стр.224] [стр.225] [стр.226] [стр.227] [стр.228] [стр.229] [стр.230] [стр.231] [стр.232] [стр.233] [стр.234] [стр.235] [стр.236] [стр.237] [стр.238] [стр.239] [стр.240] [стр.241] [стр.242] [стр.243] [стр.244] [стр.245] [стр.246] [стр.247] [стр.248] [стр.249] [стр.250] [стр.251] [стр.252] [стр.253] [стр.254] [стр.255] [стр.256] [стр.257] [стр.258] [стр.259] [стр.260] [стр.261] [стр.262] [стр.263] [стр.264] [стр.265] [стр.266] [стр.267] [стр.268] [стр.269] [стр.270] [стр.271] [стр.272] [стр.273] [стр.274] [стр.275] [стр.276] [стр.277] [стр.278] [стр.279] [стр.280] [стр.281] [стр.282] [стр.283] [стр.284] [стр.285] [стр.286] [стр.287] [стр.288] [стр.289] [стр.290] [стр.291] [стр.292] [стр.293] [стр.294]