LimitedConcurrencyLevelTaskScheduler

//--------------------------------------------------------------------------
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//
//  File: LimitedConcurrencyTaskScheduler.cs
//
//-------------------------------------------------------------------------- 

using System.Collections.Generic;
using System.Linq; 

namespace System.Threading.Tasks.Schedulers
{
    /// <summary>
    /// Provides a task scheduler that ensures a maximum concurrency level while
    /// running on top of the ThreadPool.
    /// </summary>
    public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
    {
        /// <summary>Whether the current thread is processing work items.</summary>
        [ThreadStatic]
        private static bool _currentThreadIsProcessingItems;
        /// <summary>The list of tasks to be executed.</summary>
        private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); // protected by lock(_tasks)
        /// <summary>The maximum concurrency level allowed by this scheduler.</summary>
        private readonly int _maxDegreeOfParallelism;
        /// <summary>Whether the scheduler is currently processing work items.</summary>
        private int _delegatesQueuedOrRunning = 0; // protected by lock(_tasks) 

        /// <summary>
        /// Initializes an instance of the LimitedConcurrencyLevelTaskScheduler class with the
        /// specified degree of parallelism.
        /// </summary>
        /// <param name="maxDegreeOfParallelism">The maximum degree of parallelism provided by this scheduler.</param>
        public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
        {
            if (maxDegreeOfParallelism < 1) throw new ArgumentOutOfRangeException("maxDegreeOfParallelism");
            _maxDegreeOfParallelism = maxDegreeOfParallelism;
        } 

        /// <summary>Queues a task to the scheduler.</summary>
        /// <param name="task">The task to be queued.</param>
        protected sealed override void QueueTask(Task task)
        {
            // Add the task to the list of tasks to be processed.  If there aren‘t enough
            // delegates currently queued or running to process tasks, schedule another.
            lock (_tasks)
            {
                _tasks.AddLast(task);
                if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism)
                {
                    ++_delegatesQueuedOrRunning;
                    NotifyThreadPoolOfPendingWork();
                }
            }
        } 

        /// <summary>
        /// Informs the ThreadPool that there‘s work to be executed for this scheduler.
        /// </summary>
        private void NotifyThreadPoolOfPendingWork()
        {
            ThreadPool.UnsafeQueueUserWorkItem(_ =>
            {
                // Note that the current thread is now processing work items.
                // This is necessary to enable inlining of tasks into this thread.
                _currentThreadIsProcessingItems = true;
                try
                {
                    // Process all available items in the queue.
                    while (true)
                    {
                        Task item;
                        lock (_tasks)
                        {
                            // When there are no more items to be processed,
                            // note that we‘re done processing, and get out.
                            if (_tasks.Count == 0)
                            {
                                --_delegatesQueuedOrRunning;
                                break;
                            } 

                            // Get the next item from the queue
                            item = _tasks.First.Value;
                            _tasks.RemoveFirst();
                        } 

                        // Execute the task we pulled out of the queue
                        base.TryExecuteTask(item);
                    }
                }
                // We‘re done processing items on the current thread
                finally { _currentThreadIsProcessingItems = false; }
            }, null);
        } 

        /// <summary>Attempts to execute the specified task on the current thread.</summary>
        /// <param name="task">The task to be executed.</param>
        /// <param name="taskWasPreviouslyQueued"></param>
        /// <returns>Whether the task could be executed on the current thread.</returns>
        protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
        {
            // If this thread isn‘t already processing a task, we don‘t support inlining
            if (!_currentThreadIsProcessingItems) return false; 

            // If the task was previously queued, remove it from the queue
            if (taskWasPreviouslyQueued) TryDequeue(task); 

            // Try to run the task.
            return base.TryExecuteTask(task);
        } 

        /// <summary>Attempts to remove a previously scheduled task from the scheduler.</summary>
        /// <param name="task">The task to be removed.</param>
        /// <returns>Whether the task could be found and removed.</returns>
        protected sealed override bool TryDequeue(Task task)
        {
            lock (_tasks) return _tasks.Remove(task);
        } 

        /// <summary>Gets the maximum concurrency level supported by this scheduler.</summary>
        public sealed override int MaximumConcurrencyLevel { get { return _maxDegreeOfParallelism; } } 

        /// <summary>Gets an enumerable of the tasks currently scheduled on this scheduler.</summary>
        /// <returns>An enumerable of the tasks currently scheduled.</returns>
        protected sealed override IEnumerable<Task> GetScheduledTasks()
        {
            bool lockTaken = false;
            try
            {
                Monitor.TryEnter(_tasks, ref lockTaken);
                if (lockTaken) return _tasks.ToArray();
                else throw new NotSupportedException();
            }
            finally
            {
                if (lockTaken) Monitor.Exit(_tasks);
            }
        }
    }
}
时间: 2024-10-09 10:43:27

LimitedConcurrencyLevelTaskScheduler的相关文章

《CLR via C#》之线程处理——任务调度器

<CLR via C#>之线程基础--任务调度器 <CLR via C#>之线程基础--任务调度器线程池任务调度器设置线程池限制如何管理工作者线程同步上下文任务调度器自定义TaskScheduler派生类 FCL提供了两个派生子TaskScheduler的类型:线程池任务调度器(thread pool task scheduler),和同步上下文任务调度器(synchronization context task scheduler).默认情况下都使用线程池任务调度器. 线程池任务

ENode 2.0 - 介绍一下关于ENode中对Command的调度设计

CQRS架构,C端的职责是处理从上层发送过来的command.对于单台机器来说,我们如何尽快的处理command呢?本文想通过不断提问和回答的方式,把我的思考写出来. 首先,我们最容易想到的是使用多线程.那当我们要处理一个command时,能直接丢到线程池中,直接交给线程池去调度吗?不行.因为假如多个command修改同一个聚合根时,会导致db的并发冲突,从而会导致command的不断重试,大大降低了command的处理速度. 那该怎么解决呢?既然直接多线程处理会有并发冲突的问题,那就对comm

c#与java的区别

经常有人问这种问题,用了些时间java之后,发现这俩玩意除了一小部分壳子长的还有能稍微凑合上,基本上没什么相似之处,可以说也就是马甲层面上的相似吧,还是比较短的马甲... 一般C#多用于业务系统的开发,快速实现,微软官方的各种封装,各种语法糖,使得c#在语义语法层面上更人性化,开发思路更专注于业务逻辑,对技术的实现并不需要关心的很细(当然这是指初级的入门程度),不过也带来的一些缺陷,当表面上的功夫不能满足的时候,.net程序员就不得不去了解微软封装起来的东西,所以我认识的.net程序员几乎人手一

task 限制任务数量(转自msdn)

1 public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler 2 { 3 // Indicates whether the current thread is processing work items. 4 [ThreadStatic] private static bool _currentThreadIsProcessingItems; 5 6 // The maximum concurrency level all

[更新] 基于Quartz.NET 的任务调度管理工具

更新列表: 任务参数可视化. 立即中断正在执行的任务. 每个任务独立的应用程序域 上一版参见: 基于Quqrtz.NET 做的任务调度管理工具 界面具体变化如下: 任务参数可视化 如上图所示, 在管理任务的界面上就可以知道这个任务需哪些参数/类型 及 参数的说明. 实现方式, 在 Job 上添加 特性 :  ParameterTypeAttribute 1 namespace JobA { 2 [ParameterType(typeof(Parameter))] 3 public class J