Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка ПИ Программирование на С# _Хотов.docx
Скачиваний:
4
Добавлен:
01.07.2025
Размер:
2.22 Mб
Скачать
        1. Отмена параллельных операций Parallel

Для отмены выполнения параллельных операций, запущенных с помощью методов Parallel.For() и Parallel.ForEach(), можно использовать перегруженные версии данных методов, которые принимают в качестве параметра объект ParallelOptions. Данный объект позволяет установить токен:

static void Main(string[] args)

{

CancellationTokenSource cancelTokenSource = new CancellationTokenSource();

CancellationToken token = cancelTokenSource.Token;

new Task(()=>

{

Thread.Sleep(400);

cancelTokenSource.Cancel();

}).Start();

try

{

Parallel.ForEach<int>(new List<int>() { 1,2,3,4,5,6,7,8},

new ParallelOptions { CancellationToken=token}, Factorial);

// или так

//Parallel.For(1, 8, new ParallelOptions { CancellationToken = token }, Factorial);

}

catch(OperationCanceledException ex)

{

Console.WriteLine("Операция прервана");

}

finally

{

cancelTokenSource.Dispose();

}

Console.ReadLine();

}

static void Factorial(int x)

{

int result = 1;

for (int i = 1; i <= x; i++)

{

result *= i;

}

Console.WriteLine("Факториал числа {0} равен {1}", x, result);

Thread.Sleep(3000);

}

В параллельной запущеной задаче через 400 миллисекунд происходит вызов cancelTokenSource.Cancel(), в результате программа выбрасывает исклюение OperationCanceledException, и выполнение параллельных операций прекращается.

    1. Aсинхронное программирование

В одной из прошлых глав рассматривался такой механизм как многопоточность, который позволяет выделить определенные задачи в отдельные потоки, которые будут выполняться параллельно с основной задачей. Тесно связано с многопоточностью такое понятие какасинхронность. Асинхронность позволяет вынести отдельные задачи из основного потока с специальные асинхронные методы или блоки кода. Особенно это актуально в графических программах, где продолжительные задачи могу блокировать интерфейс пользователя. И чтобы этого не произошло, нужно задействовать асинхронность. Также асинхронность несет выгоды в веб-приложениях при обработке запросов от пользователей, при обращении к базам данных или сетевым ресурсам. При больших запросах к базе данных асинхронный метод просто уснет на время, пока не получит данные от БД, а основной поток сможет продолжить свою работу. В синхронном же приложении, если бы код получения данных находился в основном потоке, этот поток просто бы блокировался на время получения данных.

Начиная с .NET 4.5 была изменена концепция создания асинхронных вызовов. Новая модель асинхронных вызовов называетсяTask-based Asynchronous Pattern или сокращенно TAP. То есть новая модель основывается на использовании задач Task. Но прежде чем перейти к нововой модели, рассмотрим, как происходили вызовы до .NET 4.5 с помощью асинхронных делегатов.

      1. Асинхронные делегаты

Асинхронные делегаты позволяют вызывать методы, на которые эти делегаты указывают, в асинхронном режиме. В теме проделегаты говорилось, что делегаты могут вызываться как с помощью метода Invoke, так и в асинхронном режиме с помощью пары методов BeginInvoke/EndInvoke. Рассмотрим на примере. Вначале посмотрим, что будет, если мы будем использовать обычный синхронный код в нашем приложении:

using System;

using System.Threading;

namespace AsyncApp

{

class Program

{

public delegate int DisplayHandler();

static void Main(string[] args)

{

DisplayHandler handler = new DisplayHandler(Display);

int result = handler.Invoke();

Console.WriteLine("Продолжается работа метода Main");

Console.WriteLine("Результат равен {0}", result);

Console.ReadLine();

}

static int Display()

{

Console.WriteLine("Начинается работа метода Display....");

int result = 0;

for (int i = 1; i < 10; i++)

{

result += i * i;

}

Thread.Sleep(3000);

Console.WriteLine("Завершается работа метода Display....");

return result;

}

}

}

Здесь создается специальный делегат DisplayHandler, который в качестве ссылки принимает метод без параметров, который возвращает число. В данном случае таким методом является метод Display, который выполняет какую-то работу. В этом случае мы получим примерно следующий вывод:

Начинается работа метода Display....

Завершается работа метода Display....

Продолжается работа метода Main

Результат равен 285

В общем-то можно было и не использовать делегат и напрямую вызвать метод Display. Но в любом случае после его вызова дальше блокируется работа метода Main, пока не завершится выполнение метода Display.

Теперь изменим пример с применением асинхронных вызовов делегата:

using System;

using System.Threading;

namespace AsyncApp

{

class Program

{

public delegate int DisplayHandler();

static void Main(string[] args)

{

DisplayHandler handler = new DisplayHandler(Display);

IAsyncResult resultObj = handler.BeginInvoke(null, null);

Console.WriteLine("Продолжается работа метода Main");

int result = handler.EndInvoke(resultObj);

Console.WriteLine("Результат равен {0}", result);

Console.ReadLine();

}

static int Display()

{

Console.WriteLine("Начинается работа метода Display....");

int result = 0;

for (int i = 1; i < 10; i++)

{

result += i * i;

}

Thread.Sleep(3000);

Console.WriteLine("Завершается работа метода Display....");

return result;

}

}

}

Суть действий практически не изменилась, тот же метод Display, только теперь он вызывается в асинхронном режиме с помощью методов BedinInvoke/EndInvoke. И теперь мы можем получить немного другой вывод:

Начинается работа метода Display....

Продолжается работа метода Main

Завершается работа метода Display....

Результат равен 285

Таким образом, после вызова метода Display через выражение handler.BeginInvoke(null, null) работа метода Main не приостанавливается. А выполнение метода Display через делегат DisplayHandler происходит в другом потоке. И лишь когда выполнение в методе Main дойдет до строки int result = handler.EndInvoke(resultObj); он блокируется и ожидает завершения выполнения метода Display.

Теперь рассмотрим особенности использования методов BeginInvoke и EndInvoke и интерфейса IAsyncResult.