Россия, Новосибирск, НГПУ, 2009 |
Программирование на языке MC#
5.4. Построения списка простых чисел методом "решета Эратосфена"
В данном разделе будет представлена параллельная программа построения списка простых чисел методом просеивания (другое название этого метода - "решето Эратосфена").
5.4.1. Наивный алгоритм
По условию задачи, по заданному натуральному числу N >= 2, необходимо найти все простые числа в интервале от 2 до N.
Метод просеивания состоит из следующих шагов:
- из исходного списка l0 всех натуральных чисел от 2 до N
l0 = [2, … , N]
выбирается первое число этого списка, а именно 2, и выдается в качестве первого выходного значения; - затем строится новый список l1, который получается из списка l0 вычеркиванием из него всех чисел, кратных очередному выбранному простому числу - на первом шаге, числу 2:
l1 = [3, 5, 7, … , N] (в предположении, что N нечетно)
- затем данная процедура повторяется рекурсивно для вновь построенного списка.
Алгоритм заканчивает свою работу, когда очередной список оказывается пустым.
В соответствии со сказанным выше, основная вычислительная процедура программы (метод Sieve), тем самым, должна производить следующие действия:
- переслать первый элемент из входного потока натуральных чисел (если он не пуст) в выходной поток;
- отфильтровать все оставшиеся числа их входного потока по модулю первого элемента и направить этот отфильтрованный поток на вход новой рекурсивно вызванной процедуре Sieve; выходным потоком для рекурсивно вызванной процедуры становится исходный выходной поток.
Выходным же каналом для этой новой процедуры будет исходный выходной канал.
Графически, один шаг рекурсивного развертывания программы может быть представлен следующим образом :
Рекурсивные вызовы метода Sieve сопровождаются созданием соответствующих объектов (класса CSieve ), имеющих каналы и обработчики. Эти каналы и обработчики используются для создания цепочки обрабатывающих элементов, с помощью которых производится просеивание потока натуральных чисел.
Программа состоит из следующих методов:
- async Sieve( handler int() getList, channel ( int ) sendPrime) - async-метод класса CSieve, который реализует собственно алгоритм просеивания: из обработчика getList предыдущего объекта цепочки читается поток чисел, фильтруется по модулю первого элемента из потока, и выбранные простые числа посылаются в канал sendPrime (через дальнейшие рекурсивные вызовы метода Sieve );
- void filter ( int p, handler int()getList, channel ( int ) cfiltered) - функция класса CSieve, реализующая фильтрацию потока натуральных чисел: из потока чисел, получаемых путем вызова обработчика getList, удаляются все элементы, которые делятся на число p, и посылаются по каналу cfiltered;
- public static void Main( String [] args )- главная функция из класса Eratosthenes, которая создает поток натуральных чисел Nats, и, по мере получения простых чисел из обработчика getPrime, выводит их на консоль.
Полный текст программы приведен ниже, а также в приложении [ "Программирование на языке MC#" ].
Как обычно, распределенный вариант программы, который может исполняться на сети машин, получается заменой ключевого слова async на movable.
В принципе, при исполнении программы на одной машине, элементы цепочки, с помощью которой производится просеивание, могут быть построены из стандартных объектов .NET, например, из очередей (объектов класса Queue ). Однако, в этом случае, программист должен позаботиться об их блокировке, что необходимо в случае одновременной работы множества синхронных методов (потоков). Использование каналов и обработчиков языка MC# освобождает программиста от этой обязанности.
Аналогично ранее рассмотренным примерам, метод Sieve выполняет слишком мало вычислительных операций, чтобы обеспечить эффективность всей параллельной (распределенной ) программы в целом.