- Task Scheduler Класс
- Определение
- Примеры
- Комментарии
- Планировщик задач по умолчанию и пул потоков The default task scheduler and the thread pool
- Глобальная очередь и локальные очереди The global queue vs. local queues
- Перенос нагрузки Work stealing
- Длительные задачи Long-running tasks
- Встраивание задач Task inlining
- Указание контекста синхронизации Specifying a synchronization context
- Конструкторы
- Свойства
- Методы
- События
- Применяется к
- Потокобезопасность
Task Scheduler Класс
Определение
Представляет объект, обрабатывающий низкоуровневую постановку задач в очередь на потоки. Represents an object that handles the low-level work of queuing tasks onto threads.
Примеры
Следующий пример взят из примеров для параллельного программирования с платформа .NET Framework 4 на веб-сайте коллекции кода MSDN. The following example is taken from the Samples for Parallel Programming with the .NET Framework 4 on the MSDN Code Gallery Web site. Он создает настраиваемый планировщик задач, ограничивающий количество потоков, используемых приложением. It creates a custom task scheduler that limits the number of threads used by the app. Затем он запускает два набора задач и отображает сведения о задаче и потоке, в котором выполняются задачи. It then launches two sets of tasks and displays information about the task and the thread on which the task is executing.
Кроме того, в галерее кода доступны несколько планировщиков заданий: примеры для параллельного программирования с помощью платформа .NET Framework 4. In addition, several sample task schedulers are available on Code Gallery: Samples for Parallel Programming with the .NET Framework 4.
Комментарии
Экземпляр TaskScheduler класса представляет планировщик задач. An instance of the TaskScheduler class represents a task scheduler. Планировщик задач гарантирует, что работа над задачей в итоге будет выполнена. A task scheduler ensures that the work of a task is eventually executed.
Планировщик заданий по умолчанию основан на пуле потоков .NET Framework 4, который обеспечивает перехват работы для балансировки нагрузки, вставку/удаление потока для максимальной пропускной способности и общее повышение производительности. The default task scheduler is based on the .NET Framework 4 thread pool, which provides work-stealing for load-balancing, thread injection/retirement for maximum throughput, and overall good performance. Его должно быть достаточно для большинства сценариев. It should be sufficient for most scenarios.
TaskSchedulerКласс также служит точкой расширения для всей настраиваемой логики планирования. The TaskScheduler class also serves as the extension point for all customizable scheduling logic. Сюда входят такие механизмы, как планирование выполнения задачи и выполнение запланированных задач для отладчиков. This includes mechanisms such as how to schedule a task for execution, and how scheduled tasks should be exposed to debuggers. Если требуются специальные функции, можно создать пользовательский планировщик и включить его для определенных задач или запросов. If you require special functionality, you can create a custom scheduler and enable it for specific tasks or queries.
Планировщик задач по умолчанию и пул потоков The default task scheduler and the thread pool
Планировщик по умолчанию для библиотеки параллельных задач и PLINQ использует пул потоков платформа .NET Framework, представленный ThreadPool классом, для постановки в очередь и выполнения работы. The default scheduler for the Task Parallel Library and PLINQ uses the .NET Framework thread pool, which is represented by the ThreadPool class, to queue and execute work. Пул потоков использует сведения, предоставляемые Task типом для эффективной поддержки детализированного параллелизма (кратковременных единиц работы), которые часто представляют параллельные задачи и запросы. The thread pool uses the information that is provided by the Task type to efficiently support the fine-grained parallelism (short-lived units of work) that parallel tasks and queries often represent.
Глобальная очередь и локальные очереди The global queue vs. local queues
Пул потоков поддерживает глобальную очередь FIFO (по принципу «первым поступил — первым обслужен») для потоков в каждом домене приложения. The thread pool maintains a global FIFO (first-in, first-out) work queue for threads in each application domain. Всякий раз, когда программа вызывает ThreadPool.QueueUserWorkItem метод (или ThreadPool.UnsafeQueueUserWorkItem ), работа помещается в эту общую очередь и в конечном итоге удаляется из очереди в следующий поток, который становится доступным. Whenever a program calls the ThreadPool.QueueUserWorkItem (or ThreadPool.UnsafeQueueUserWorkItem) method, the work is put on this shared queue and eventually de-queued onto the next thread that becomes available. Начиная с платформа .NET Framework 4, эта очередь была улучшена для использования алгоритма без блокировки, похожего на ConcurrentQueue класс. Starting with the .NET Framework 4, this queue has been improved to use a lock-free algorithm that resembles the ConcurrentQueue class. Используя эту реализацию без блокировки, пул потоков тратит меньше времени, когда он помещает рабочие элементы в очередь и освобождает их. By using this lock-free implementation, the thread pool spends less time when it queues and de-queues work items. Это преимущество производительности доступно для всех программ, использующих пул потоков. This performance benefit is available to all programs that use the thread pool.
Задачи верхнего уровня, которые являются задачами, не созданными в контексте других задач, помещаются в глобальную очередь так же, как и другие рабочие элементы. Top-level tasks, which are tasks that are not created in the context of another task, are put on the global queue just like any other work item. Однако вложенные или дочерние задачи, создаваемые в контексте других задач, обрабатываются по-другому. However, nested or child tasks, which are created in the context of another task, are handled quite differently. Дочерняя или вложенная задача помещается в локальную очередь, относящуюся к потоку, в котором выполняется родительская задача. A child or nested task is put on a local queue that is specific to the thread on which the parent task is executing. Родительская задача может быть задачей верхнего уровня или дочерней задачей другой задачи. The parent task may be a top-level task or it also may be the child of another task. Когда этот поток готов для дополнительной работы, сначала он выполняет поиск в локальной очереди. When this thread is ready for more work, it first looks in the local queue. Если в ней существует ожидающие рабочие элементы, к ним возможен быстрый доступ. If work items are waiting there, they can be accessed quickly. Доступ к локальным очередям осуществляется по принципу «последним порядку выхода» (ЛИФО), чтобы сохранить локальность кэша и уменьшить состязание. The local queues are accessed in last-in, first-out order (LIFO) to preserve cache locality and reduce contention. Дополнительные сведения о дочерних задачах и вложенных задачах см. в разделе присоединенные и отсоединенные дочерние задачи. For more information about child tasks and nested tasks, see Attached and Detached Child Tasks.
Использование локальных очередей не только сокращает нагрузку на глобальную очередь, но и использует преимущества локального использования данных. The use of local queues not only reduces pressure on the global queue, but also takes advantage of data locality. Рабочие элементы в локальной очереди часто ссылаются на структуры данных, которые физически находятся рядом друг с другом в памяти. Work items in the local queue frequently reference data structures that are physically near one another in memory. В этих случаях данные уже находятся в кэше после выполнения первой задачи и могут быть быстро доступны. In these cases, the data is already in the cache after the first task has run and can be accessed quickly. Параллельный LINQ (PLINQ) и Parallel класс используют вложенные задачи и дочерние задачи широко и обеспечивают значительное ускорение с помощью локальных рабочих очередей. Both Parallel LINQ (PLINQ) and the Parallel class use nested tasks and child tasks extensively, and achieve significant speedups by using the local work queues.
Перенос нагрузки Work stealing
Начиная с платформа .NET Framework 4, пул потоков также применяет алгоритм переноса нагрузки, позволяющий убедиться, что потоки не находятся в состоянии простоя, а другие еще работают в своих очередях. Starting with the .NET Framework 4, the thread pool also features a work-stealing algorithm to help make sure that no threads are sitting idle while others still have work in their queues. Когда поток из пула потоков готов для дополнительной работы, сначала он выполняет поиск в своей локальной очереди, далее в глобальной очереди, а затем в локальных очередях других потоков. When a thread-pool thread is ready for more work, it first looks at the head of its local queue, then in the global queue, and then in the local queues of other threads. При обнаружении рабочего элемента в локальной очереди другого потока он сначала применяет эвристику, чтобы убедиться, что он может эффективно выполнить эту работу. If it finds a work item in the local queue of another thread, it first applies heuristics to make sure that it can run the work efficiently. Если он может, то выводит этот рабочий элемент с конца очереди (в порядке ФИФО). If it can, it de-queues the work item from the tail (in FIFO order). Это уменьшает конкуренцию внутри каждой из локальных очередей и сохраняет локальность данных. This reduces contention on each local queue and preserves data locality. Эта архитектура позволяет повысить эффективность балансировки нагрузки пула потоков по сравнению с предыдущими версиями. This architecture helps the thread pool load-balance work more efficiently than past versions did.
Длительные задачи Long-running tasks
Может потребоваться явно запретить помещение задачи в локальную очередь. You may want to explicitly prevent a task from being put on a local queue. Например, вы знаете, что определенный рабочий элемент будет выполняться довольно долго и может заблокировать другие рабочие элементы в локальной очереди. For example, you may know that a particular work item will run for a relatively long time and is likely to block all other work items on the local queue. В таком случае можно указать параметр System.Threading.Tasks.TaskCreationOptions, который подсказывает планировщику, что для задачи может потребоваться дополнительный поток, чтобы она не блокировала дальнейший ход работы других потоков или рабочих элементов в локальной очереди. In this case, you can specify the System.Threading.Tasks.TaskCreationOptions option, which provides a hint to the scheduler that an additional thread might be required for the task so that it does not block the forward progress of other threads or work items on the local queue. С помощью этого параметра можно полностью избежать пула потоков, включая глобальные и локальные очереди. By using this option you avoid the thread pool completely, including the global and local queues.
Встраивание задач Task inlining
В некоторых случаях, когда Task ожидается, он может выполняться синхронно в потоке, который выполняет операцию ожидания. In some cases when a Task is waited on, it may be executed synchronously on the thread that is performing the wait operation. Это повышает производительность, предотвращая необходимость в дополнительном потоке и вместо этого использует существующий поток, который в противном случае был бы заблокирован. This enhances performance by preventing the need for an additional thread and instead using the existing thread, which would have blocked otherwise. Чтобы предотвратить возникновение ошибок из-за повторного входа, встраивание задачи происходит только в том случае, если целевой объект ожидания находится в локальной очереди соответствующего потока. To prevent errors due to reentrancy, task inlining only occurs when the wait target is found in the relevant thread’s local queue.
Указание контекста синхронизации Specifying a synchronization context
С помощью метода TaskScheduler.FromCurrentSynchronizationContext можно указать, что задачу необходимо планировать для запуска в определенном потоке. You can use the TaskScheduler.FromCurrentSynchronizationContext method to specify that a task should be scheduled to run on a particular thread. Это полезно на платформах, например Windows Forms и Windows Presentation Foundation, где доступ к объектам пользовательского интерфейса часто ограничен кодом, выполняемым в том же потоке, в котором был создан этот объект пользовательского интерфейса. This is useful in frameworks such as Windows Forms and Windows Presentation Foundation where access to user interface objects is often restricted to code that is running on the same thread on which the UI object was created.
В следующем примере TaskScheduler.FromCurrentSynchronizationContext метод в приложении Windows Presentation Foundation (WPF) используется для планирования задачи в том же потоке, в котором был создан элемент управления пользовательского интерфейса. The following example uses the TaskScheduler.FromCurrentSynchronizationContext method in a Windows Presentation Foundation (WPF) app to schedule a task on the same thread that the user interface (UI) control was created on. В примере создается мозаика из изображений, которые выбираются случайным образом из указанного каталога. The example creates a mosaic of images that are randomly selected from a specified directory. Объекты WPF используются для загрузки и изменения размера изображений. The WPF objects are used to load and resize the images. Необработанные пиксели затем передаются в задачу, которая использует For цикл для записи пиксельных данных в большой однобайтовый массив. The raw pixels are then passed to a task that uses a For loop to write the pixel data into a large single-byte array. Синхронизация не требуется, поскольку две плитки не занимают одни и те же элементы массива. No synchronization is required because no two tiles occupy the same array elements. Плитки также можно записать в любом порядке, так как их расположение вычисляется независимо от любой другой плитки. The tiles can also be written in any order because their position is calculated independently of any other tile. После этого большой массив передается задаче, выполняемой в потоке пользовательского интерфейса, в котором данные пикселей загружаются в элемент управления Image. The large array is then passed to a task that runs on the UI thread, where the pixel data is loaded into an Image control.
В примере данные перемещаются из потока пользовательского интерфейса, изменяются с помощью параллельных циклов и Task объектов, а затем передаются обратно в задачу, выполняемую в потоке пользовательского интерфейса. The example moves data off the UI thread, modifies it by using parallel loops and Task objects, and then passes it back to a task that runs on the UI thread. Этот подход удобен, когда необходимо использовать библиотеку параллельных задач для выполнения операций, которые либо не поддерживаются API WPF, либо не выполняются достаточно быстро. This approach is useful when you have to use the Task Parallel Library to perform operations that either are not supported by the WPF API, or are not sufficiently fast. Другим способом создания мозаики изображений в WPF является использование System.Windows.Controls.WrapPanel элемента управления и добавление в него изображений. Another way to create an image mosaic in WPF is to use a System.Windows.Controls.WrapPanel control and add images to it. WrapPanelОбрабатывает работу по размещению плиток. The WrapPanel handles the work of positioning the tiles. Однако эту работу можно выполнить только в потоке пользовательского интерфейса. However, this work can only be performed on the UI thread.
Чтобы создать пример, создайте проект приложения WPF в Visual Studio и назовите его WPF_CS1 (для проекта C# WPF) или WPF_VB1 (для Visual Basic проекта WPF). To create the example, create a WPF application project in Visual Studio and name it WPF_CS1 (for a C# WPF project) or WPF_VB1 (for a Visual Basic WPF project). После этого выполните описанные ниже действия. Then do the following:
В режиме конструктора перетащите Image элемент управления из области элементов в левый верхний угол области конструктора. In design view, drag an Image control from the Toolbox onto the upper left corner of the design surface. В текстовом поле имя окна свойства назовите элемент управления «Image». In the Name textbox of the Properties window, name the control «image».
Перетащите Button элемент управления из области элементов в нижнюю левую часть окна приложения. Drag a Button control from the Toolbox to the lower left part of the application window. В представлении XAML укажите Content свойство кнопки как «создать мозаику» и укажите его Width свойство как «100». In XAML view, specify the Content property of the button as «Make a mosaic», and specify its Width property as «100». Соедините Click событие с button_Click обработчиком событий, определенным в коде примера, добавив Click=»button_Click» к элементу. Connect the Click event with the button_Click event handler defined in the example’s code by adding Click=»button_Click» to the element. В текстовом поле имя окна свойства назовите элемент управления «Кнопка». In the Name textbox of the Properties window, name the control «button».
Замените все содержимое файла MainWindow. XAML. cs или MainWindow. XAML. vb кодом из этого примера. Replace the entire contents of the MainWindow.xaml.cs or MainWindow.xaml.vb file with the code from this example. Для проекта C# WPF убедитесь, что имя рабочей области совпадает с именем проекта. For a C# WPF project, make sure that the name of the workspace matches the project name.
Пример считывает изображения JPEG из каталога с именем К:\усерс\публик\пиктурес\сампле pictures \ . The example reads JPEG images from a directory named C:\Users\Public\Pictures\Sample Pictures\. Либо создайте каталог и поместите в него некоторые образы, либо измените путь, чтобы он ссылался на другой каталог, содержащий образы. Either create the directory and place some images in it, or change the path to refer to some other directory that contains images.
Этот пример имеет некоторые ограничения. This example has some limitations. Например, поддерживаются только изображения размером 32 бит на пиксель; изображения в других форматах повреждаются BitmapImage объектом во время операции изменения размера. For example, only 32-bits-per-pixel images are supported; images in other formats are corrupted by the BitmapImage object during the resizing operation. Кроме того, исходные изображения должны быть больше, чем размер плитки. Also, the source images must all be larger than the tile size. В качестве дальнейшего упражнения можно добавить функциональные возможности для обработки нескольких форматов пикселей и размеров файлов. As a further exercise, you can add functionality to handle multiple pixel formats and file sizes.
Конструкторы
Инициализирует объект TaskScheduler. Initializes the TaskScheduler.
Свойства
Получает объект TaskScheduler, связанный с выполняемой в настоящий момент задачей. Gets the TaskScheduler associated with the currently executing task.
Получает экземпляр TaskScheduler по умолчанию, предоставляемый .NET. Gets the default TaskScheduler instance that is provided by .NET.
Получает уникальный идентификатор данного объекта TaskScheduler. Gets the unique ID for this TaskScheduler.
Указывает максимальный уровень параллелизма, который может поддерживаться данным планировщиком TaskScheduler. Indicates the maximum concurrency level this TaskScheduler is able to support.
Методы
Определяет, равен ли указанный объект текущему объекту. Determines whether the specified object is equal to the current object.
(Унаследовано от Object)
Освобождает все ресурсы, связанные с данным планировщиком. Frees all resources associated with this scheduler.
Создает TaskScheduler для связывания с текущим элементом SynchronizationContext. Creates a TaskScheduler associated with the current SynchronizationContext.
Служит хэш-функцией по умолчанию. Serves as the default hash function.
(Унаследовано от Object)
Создает перечисляемый объект экземпляров Task, которые в настоящее время находятся в очереди планировщика, ожидая выполнения (только для поддержки отладки). For debugger support only, generates an enumerable of Task instances currently queued to the scheduler waiting to be executed.
Возвращает объект Type для текущего экземпляра. Gets the Type of the current instance.
(Унаследовано от Object)
Создает неполную копию текущего объекта Object. Creates a shallow copy of the current Object.
(Унаследовано от Object)
Ставит объект Task в очередь планировщика. Queues a Task to the scheduler.
Возвращает строку, представляющую текущий объект. Returns a string that represents the current object.
(Унаследовано от Object)
Пытается удалить из очереди задачу Task, ранее поставленную в очередь данного планировщика. Attempts to dequeue a Task that was previously queued to this scheduler.
Пытается выполнить предоставленную задачу Task в этом планировщике. Attempts to execute the provided Task on this scheduler.
Определяет, можно ли выполнить предоставленную задачу Task в этом вызове синхронно, и если возможно, выполняет ее. Determines whether the provided Task can be executed synchronously in this call, and if it can, executes it.
События
Создается при активации политики эскалации исключений из-за непредвиденного исключения задачи, завершившейся сбоем. По умолчанию из-за этой политики процесс будет прерван. Occurs when a faulted task’s unobserved exception is about to trigger exception escalation policy, which, by default, would terminate the process.
Применяется к
Потокобезопасность
Все члены абстрактного TaskScheduler типа являются потокобезопасными и могут использоваться из нескольких потоков одновременно. All members of the abstract TaskScheduler type are thread-safe and may be used from multiple threads concurrently.