В программах, исполняющихся последовательно, в каждый момент времени может возникнуть только одно ,
Основные принципы работы с исключительными ситуациями при использовании библиотеки PFX состоят в следующем:
Parallel .For, это исключение обрабатывается средствами самой библиотеки (если, конечно, перехват этого исключения не был предусмотрен самим программистом) и перенаправляется в ту задачу, которая ожидает завершения данной;Parallel .Invoke ), все они собираются в единое исключение типа System.Threading .AggregateException, которые переправляются дальше по цепочке вызовов задач;AggregateException в целях единообразной обработки всех AggregateException могут возникать при работе со следующими конструкциями библиотеки PFX:
Parallel - исключения могут возникнуть в параллельно исполняющихся итерациях циклов Parallel .For\Parallel .ForEach или в параллельно исполняющихся блоках кода при работе с Parallel .Invoke ;Task - исключения, возникшие в теле задачи, будут повторно возбуждены в месте вызова метода Wait данной задачи. Кроме того, объект возникшего исключения доступен через свойство Task.Exception ;Future<T> - исключения, возникшие в теле задачи, будут повторно возбуждены в месте вызова метода Wait (унаследованного от класса Task ) или в месте обращения к свойству Future<T>.Value ;ForAll (), ToList(), ToArray(), ToDictionary(), ToLookup(), MoveNext() и при работе с GetEnumerator() (например в цикле foreach ).Имея представление о потенциальных местах, где могут возникнуть try-catch, оставляя для главной задачи (корня иерархии) только функции управления исключительными ситуациями для задач более низкого уровня.
Например, при
public static void ProcessImages(string path)
{
Parallel.ForEach(GetImageFiles(path), imageFilePath =>
{
try
{
Bitmap bmp = new Bitmap(imageFilePath);
ProcessImage(bmp);
}
catch (UnauthorizedAccessException uae)
{
HandleUnauthorizedAccessException(uae);
}
catch (FileNotFoundException fnfe)
{
HandleFileNotFoundExceptions(fnfe);
}
});
}
Здесь, возникновение UnauthorizedAccessException и FileNotFoundException для одного из изображений не повлияет на параллельную обработку остальных изображений. При возникновении
При исполнении параллельной конструкции можно воспользоваться другим подходом, при котором все
var exceptions = new ConcurrentStack<Exception>();
Parallel.For(0, N, i=>
{
try
{
Process(i);
}
catch(Exception exc) { exceptions.Push(exc); }
}
if (!exceptions.IsEmpty) throw new AggregateException(exceptions);
В состав PFX входят так называемые координационные структуры данных, среди которых имеются структуры для безопасного применения в многопоточной среде такие как, например, ConcurrentQueue<T> и СoncurrentStack<T>.
PFX-аналоги классов, содержащихся в пространстве имен System.Collections, имеют, во многом, сходные с ними свойства. Так, например, для объектов обоих видов классов допускается перечисление элементов этих объектов с помощью цикла foreach. Однако, стоит обратить вниманте, что для объектов обычных классов-коллекций запрещена модификация этих объектов в процессе перечисления. Например, выполнение кода, приведенного ниже, вызовет исключительную ситуацию InvalidOperationException: "Collection was :
var q = new Queue<int> (new[] { 1, 2, 3, 4, 5 });
foreach (var item in q)
{
if (item <= 5) q.Enqueue(item * 6);
}
Если же изменить на тип ConcurrentQueue<int>:
var q = new ConcurrentQueue<int> (new[] { 1, 2, 3, 4, 5 });
foreach (var item in q)
{
if (item <= 5) q.Enqueue(item * 6);
}
то выполнение такого кода уже не вызовет foreach, согласно правил, зафиксированных в текущей реализации библиотеки PFX, в очереди будет находиться 10 элементов.
Такое изменение свойств объектов-коллекций было специально принято в PFX, поскольку
Задача 1.
Перечислите элементы, которые будут содержаться в очереди, после выполнения следующего кода:
var q = new ConcurrentQueue<int> (new[] { 1, 2, 3, 4, 5 });
foreach (var item in q)
{
if (item <= 5) q.Enqueue(item * 6);
}
При
for (int i = 0; i < numberOfFrames; i++)
{
var frame = GenerateFrame(i);
WriteToMovie(frame);
}
Этот же алгоритм можно реализовать и с помощью средств
var frames = from i in Enumerable.Range(0, numberOfFrames)
select GenerateFrame(i);
foreach (var frame in frames) WriteToMovie(frame);
Выполнение метода GenerateFrame может занимать достаточно много времени, поэтому имеет смысл распараллелить генерацию видеокадров. Для примера, предположим, что исполнение метода GenerateFrame в отдельном потоке является безопасным (т.е., использование общих данных, если таковые имеются, одновременно с другими потоками происходит корректно), и что порождение очередного кадра не зависит от предыдущих кадров. При параллельной генерации отдельных кадров, необходимо, тем не менее, предусмотреть средства
using (ManualResetEvent mre = new ManualResetEvent(false))
{
int count = numberOfFrames;
object obj = new object();
for (int i = 0; i < numberOfFrames; i++)
{
ThreadPool.QueueUserWorkItem(state =>
{
var frame = GenerateFrame((int)state);
lock(obj) WriteToMovie(frame);
if (Interlocked.Decrement(ref count) == 0)
mre.Set();
}, i );
}
mre.WaitOne();
}
Легко видеть, что полученное параллельное решение имеет серьезный недостаток - оно не обеспечивает правильный порядок сгенерированных кадров в результирующем видеофайле. Сохранить порядок ManualResetEvent:
var frames = new Bitmap[numberOfFrames];
var events = (from i in Enumerable.Range(0, numberOfFrames)
select new ManualResetEvent(false)).ToArray();
for (int i = 0; i < numberOfFrames; i++)
{
ThreadPool.QueueUserWorkItem(state =>
{
int frameNum = (int)state;
frames[frameNum] = GenerateFrame(frameNum);
events[frameNum].Set();
}, i);
}
for (int i = 0; i < numberOfFrames; i++)
{
events[i].WaitOne();
WriteToMovie(frames[i]);
}
Представленный выше код является корректным - он обеспечивает правильный порядок кадров в результирующем видеофайле, но не эффективным. Неэффективность состоит в том, что на каждый генерируемый кадр заводится отдельное событие ManualResetEvent, которое реализуется через исполнение некоторого кода из ядра операционной системы. Замен событий можно воспользоваться классом Future<T> для реализации того же алгоритма:
var frames = (from i in Enumerable.Range(0, numberOfFrames)
select Future.Create(() => GenerateFrame(i))).
ToArray();
foreach (var frame in frames) WriteToMovie(frame.Value);
В приведенном выше фрагменте, вместо массива событий создается массив объектов класса Future<T>. Исполнение соответствующих им делегатов происходит параллельно, а при последовательной записи кадров в видеофайл происходит ожидание завершения работы соответствующего делегата. Код стал более кратким и более эффективным.
Возможен еще один вариант решения этой задачи, в котором не используются средства Future<T> задействована очередь:
var frames = new Queue<Future<Bitmap> > ();
for (int i = 0; i < numberOfFrames; i++)
{
var num = i;
frames.Enqueue(Future.Create(() => GenerateFrame(num)));
}
while (frames.Count > 0) WriteToMovie(frames.Dequeue().Value);
Наконец, для решения этой задачи средствами PLINQ, можно применить опцию PreserveOrdering перечисления ParallelQueryOptions:
var frames = from i in Enumerable.Range(0, numberOfFrames).
AsParallel(ParallelQueryOptions.PreserveOrdering)
select GenerateFrame(i);
foreach (var frame in frames) WriteToMovie(frame);
Задача 1.
Пусть дан массив A, содержащий натуральные числа, большие 1. Напишите параллельную программу, которая записывает в другой массив B все простые числа из массива A, сохраняя их относительный порядок в исходном массиве. Т.е., если массив A содержит, например, числа 14,13,21,25,31,20,17, то массив B должен содержать числа 13, 31, 17 в указанном порядке.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.