Главная страница

лабараторная работа. Теория_к_лабораторным. 1. Применение параллельных вычислений


Скачать 0.7 Mb.
Название1. Применение параллельных вычислений
Анкорлабараторная работа
Дата24.10.2021
Размер0.7 Mb.
Формат файлаdoc
Имя файлаТеория_к_лабораторным.doc
ТипДокументы
#254886
страница2 из 9
1   2   3   4   5   6   7   8   9

3. Конструкция Parallel.For


Конструкции Parallel стали доступны с появлением .NET 4.0. С их использованием достаточно легко реализовать параллельные вычисления, если не требуется отдельно контролировать ход выполнения каждого отдельного потока. Далее представлен фрагмент кода из демонстрационной программы, работу которого вы можете наблюдать, запустив эту самую демонстрационную программу и нажав кнопку [Старт] на первой закладке. Код реализует выполнение цикла, аналогичногоциклу for, но с той лишь разницей, что каждая итерация выполняется в отдельном потоке. Пример построен таким образом, что некоторые итерации могут так и не “засветиться” в отчете о работе, поскольку за них всю работу выполнили другие итерации.

Теперь более подробно. Задано определенное количество параллельных потоков, для каждого из которых конструкцией Parallel.For создается отдельный поток или нить исполнения - Thread. Каждый такой поток выполняет действия, описанные методом _DoWork() до тех пор, пока общий счетчик _SharedCount не достигнет своего максимума. Максимальное значение _SharedCount определяется, как квадрат от заданного количества потоков. Система распределяет процессорное время по своему усмотрению, по известным только ей правилам и законам, и может случиться так, что некоторые итерации так и не успеют ни разу выполнить тело циклаwhile() {}. У каждого потока имеется свой собственный счетчик выполнения _DoWork(). Пример работы демонстрационной программы представлен ниже. Видно, что 4 из 10 потоков так ни разу и не “приложились к общему делу”, а некоторые из потоков успели это сделать аж 26 раз.


Пример работы программы с конструкцией Parallel.For.

Подробно комментировать пример не буду, поскольку комментариев хватает в самом коде, но прошу обратить внимание на то, каким образом организован безопасный доступ к разделяемым потоками ресурсам. В нашем случае это общий счетчик _SharedCount и журнал сообщений _Log. Разграничение доступа заключается в том чтобы не дать двум и более потокам одновременно редактировать разделяемый ими ресурс, поскольку это может привести к непредсказуемым последствиям и просто аварийному завершению программы.

//Пример 1. Parallel.For

private void btnStartParallelFor_Click(object sender, EventArgs e)

{

textBoxParallelFor.Text = string.Empty;

//Количество потоков

int _ThreadsCount = Convert.ToInt32(numericUpDownThreadsCount.Value);

//Массив счетчиков для создаваемых потоков

int[] _Counts = new int[_ThreadsCount];

//Общий счетчик - разделяемый ресурс

int _SharedCount = 0;

//Журнал сообщений

string _Log = string.Empty;

//Объект - блокировка для разграничения доступа к журналу

object _LogLock = new object();

//Количество итераций

int _SharedCountMax = _ThreadsCount * _ThreadsCount;

//Универсальный делегат - тело цикла с параллельной обработкой итераций

Action<int> _ForAction = (i) =>

{

while (_SharedCount < _SharedCountMax)

{

//Имитация 'бурной деятельности'

_DoWork();

//Каждый поток имеет свой счетчик, поэтому разграничение доступа не требуется

_Counts[i]++;

//Потокобезопасная операция инкремента (_SharedCount++)

//Операции Interlocked являются атомарными и не требуют блокировок типа lock() {}

//Это позволяет избежать потерь в производительности, связанных с блокировками

Interlocked.Increment(ref _SharedCount);

//Потокобезопасная модификация _Log с использованием блокировки

lock (_LogLock)

{

_Log = _Log + "Общий счетчик: " + _SharedCount.ToString()

+ "; Счетчки[" + i.ToString()

+ "]: " + _Counts[i].ToString() + Environment.NewLine;

}

}

};

//Цикл с параллельной обработкой итераций: for (int i = 0; i < _ThreadsCount; i++) _ForAction(i)

Parallel.For(0, _ThreadsCount, _ForAction);

//Формирование и вывод отчета

_Log = _Log + Environment.NewLine +"Итог:" + Environment.NewLine;

for (int i = 0; i < _ThreadsCount; i++)

_Log = _Log + "Счетчик[" + i.ToString() + "]: " + _Counts[i].ToString() + Environment.NewLine;

textBoxParallelFor.Text = _Log;

}

//Имитация обработки данных

internal void _DoWork()

{

int _Iterations = Convert.ToInt32(numericUpDownWork.Value);

for (int i = 0; i < _Iterations; i++)

for (int j = 0; j < 100000; j++) { }

}
1   2   3   4   5   6   7   8   9


написать администратору сайта