Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

Следующий шаг связан с конфигурированием экземпляра делегата

TimerCallback
и передачей его объекту
Timer
. В дополнение к настройке делегата
TimerCallback
конструктор
Timer
позволяет указывать необязательный информационный параметр для передачи целевому методу делегата (определенный как
System.Object
), интервал вызова метода и период ожидания (в миллисекундах), который должен истечь перед первым вызовом. Вот пример:

Console.WriteLine("***** Working with Timer type *****\n");

// Создать делегат для типа Timer.

TimerCallback timeCB = new TimerCallback(PrintTime);

//
Установить параметры таймера.

Timer t = new Timer(

timeCB, // Объект делегата TimerCallback.

null, // Информация для передачи в вызванный метод.

// (null, если информация отсутствует).

0, // Период ожидания перед запуском (в миллисекундах).

1000); // Интервал между вызовами (в миллисекундах).

Console.WriteLine("Hit Enter key to terminate...");

Console.ReadLine;

В этом случае метод

PrintTime
вызывается приблизительно каждую секунду и не получает никакой дополнительной информации. Ниже показан вывод примера:

***** Working with Timer type *****

Hit key to terminate...

Time is: 6:51:48 PM

Time is: 6:51:49 PM

Time is: 6:51:50 PM

Time is: 6:51:51 PM

Time is: 6:51:52 PM

Press any key to continue ...

Чтобы передать целевому методу делегата какую-то информацию, необходимо просто заменить значение

null
во втором параметре конструктора подходящей информацией, например:

// Установить параметры таймера.

Timer t = new Timer(timeCB, "Hello From C# 9.0", 0, 1000);

You can then obtain the incoming data as follows:static void PrintTime(object state)

{

Console.WriteLine("Time is: {0}, Param is: {1}",

DateTime.Now.ToLongTimeString, state.ToString);

}

Использование автономного отбрасывания (нововведение в версии 7.0)

В предыдущем примере переменная

Timer
не применяется в каком-либо пути выполнения и потому может быть заменена отбрасыванием:

var _ = new Timer(

timeCB, // Объект делегата TimerCallback.

null, // Информация для передачи в вызванный метод

// (null, если информация отсутствует).

0, // Период ожидания перед запуском

// (в миллисекундах).

1000); // Интервал между вызовами

// (в миллисекундах).

Класс ThreadPool

Следующей темой о потоках, которую мы рассмотрим в настоящей главе, будет роль пула потоков. Запуск нового потока связан с затратами, поэтому в целях повышения эффективности пул потоков удерживает созданные (но неактивные) потоки до тех пор, пока они не понадобятся. Для взаимодействия с этим пулом ожидающих потоков в пространстве имен

System.Threading
предлагается класс
ThreadPool
.

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

ThreadPool.QueueUserWorkItem
. Он имеет перегруженную версию, которая позволяет в дополнение к экземпляру делегата
WaitCallback
указывать необязательный параметр
System.Object
для передачи специальных данных состояния:

public static class ThreadPool

{

...

public static bool QueueUserWorkItem(WaitCallback callBack);

public static bool QueueUserWorkItem(WaitCallback callBack,

object state);

}

Делегат

WaitCallback
может указывать на любой метод, который принимает в качестве единственного параметра экземпляр
System.Object
(представляющий необязательные данные состояния) и ничего не возвращает. Обратите внимание, что если при вызове
QueueUserWorkItem
не задается экземпляр
System.Object
, то среда .NET Core Runtime автоматически передает значение
null
. Чтобы продемонстрировать работу методов очередей, работающих с пулом потоков .NET Core Runtime, рассмотрим еще раз программу (в проекте консольного приложения по имени
ThreadPoolApp
), в которой применяется тип
Printer
. На этот раз массив объектов
Thread
не создается вручную, а метод
PrintNumbers
будет назначаться членам пула потоков:

using System;

using System.Threading;

using ThreadPoolApp;

Console.WriteLine("***** Fun with the .NET Core Runtime Thread Pool *****\n");

Console.WriteLine("Main thread started. ThreadID = {0}",

Thread.CurrentThread.ManagedThreadId);

Printer p = new Printer;

WaitCallback workItem = new WaitCallback(PrintTheNumbers);

// Поставить в очередь метод десять раз.

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

{

ThreadPool.QueueUserWorkItem(workItem, p);

}

Console.WriteLine("All tasks queued");

Console.ReadLine;

static void PrintTheNumbers(object state)

{

Printer task = (Printer)state;

task.PrintNumbers;

}

У вас может возникнуть вопрос: почему взаимодействовать с пулом потоков, поддерживаемым средой .NET Core Runtime, выгоднее по сравнению с явным созданием объектов

Thread
? Использование пула потоков обеспечивает следующие преимущества.

• Пул потоков эффективно управляет потоками, сводя к минимуму количество потоков, которые должны создаваться, запускаться и останавливаться.

• За счет применения пула потоков можно сосредоточиться на решении задачи, а не на потоковой инфраструктуре приложения.

Поделиться с друзьями: