C# Task 多任务 限制Task并发数量

LimitedTaskScheduler:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Utils
{
    public class LimitedTaskScheduler : TaskScheduler, IDisposable
    {
        #region 外部方法
        [DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")]
        public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
        #endregion

        #region 变量属性事件
        private BlockingCollection<Task> _tasks = new BlockingCollection<Task>();
        List<Thread> _threadList = new List<Thread>();
        private int _threadCount = 0;
        private int _timeOut = Timeout.Infinite;
        private Task _tempTask;
        #endregion

        #region 构造函数
        public LimitedTaskScheduler(int threadCount = 10)
        {
            CreateThreads(threadCount);
        }
        #endregion

        #region override GetScheduledTasks
        protected override IEnumerable<Task> GetScheduledTasks()
        {
            return _tasks;
        }
        #endregion

        #region override TryExecuteTaskInline
        protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
        {
            return false;
        }
        #endregion

        #region override QueueTask
        protected override void QueueTask(Task task)
        {
            _tasks.Add(task);
        }
        #endregion

        #region 资源释放
        /// <summary>
        /// 资源释放
        /// 如果尚有任务在执行,则会在调用此方法的线程上引发System.Threading.ThreadAbortException,请使用Task.WaitAll等待任务执行完毕后,再调用该方法
        /// </summary>
        public void Dispose()
        {
            _timeOut = 100;

            foreach (Thread item in _threadList)
            {
                item.Abort();
            }
            _threadList.Clear();

            GC.Collect();
            GC.WaitForPendingFinalizers();
            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
            {
                SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
            }
        }
        #endregion

        #region 创建线程池
        /// <summary>
        /// 创建线程池
        /// </summary>
        private void CreateThreads(int? threadCount = null)
        {
            if (threadCount != null) _threadCount = threadCount.Value;
            _timeOut = Timeout.Infinite;

            for (int i = 0; i < _threadCount; i++)
            {
                Thread thread = new Thread(new ThreadStart(() =>
                {
                    Task task;
                    while (_tasks.TryTake(out task, _timeOut))
                    {
                        TryExecuteTask(task);
                    }
                }));
                thread.IsBackground = true;
                thread.Start();
                _threadList.Add(thread);
            }
        }
        #endregion

        #region 全部取消
        /// <summary>
        /// 全部取消
        /// </summary>
        public void CancelAll()
        {
            while (_tasks.TryTake(out _tempTask)) { }
        }
        #endregion

    }
}

ThreadHelper(Run方法没有使用LimitedTaskScheduler,Run2方法使用了LimitedTaskScheduler):

using System;
using System.Windows.Threading;
using System.Threading;
using System.Threading.Tasks;

namespace Utils
{
    /// <summary>
    /// 线程帮助类(处理单线程任务)
    /// </summary>
    public class ThreadHelper
    {
        private static LimitedTaskScheduler _defaultScheduler = new LimitedTaskScheduler();

        /// <summary>
        /// 执行 
        /// 例:ThreadHelper.Run(() => { }, (ex) => { });
        /// </summary>
        /// <param name="doWork">在线程中执行</param>
        /// <param name="errorAction">错误处理</param>
        public static System.Threading.Tasks.Task Run2(Action doWork, LimitedTaskScheduler scheduler = null, Action<Exception> errorAction = null)
        {
            if (scheduler == null) scheduler = _defaultScheduler;
            System.Threading.Tasks.Task task = System.Threading.Tasks.Task.Factory.StartNew(() =>
            {
                try
                {
                    if (doWork != null)
                    {
                        doWork();
                    }
                }
                catch (Exception ex)
                {
                    if (errorAction != null) errorAction(ex);
                    LogUtil.LogError(ex);
                }
            }, CancellationToken.None, TaskCreationOptions.None, scheduler);
            return task;
        }

        /// <summary>
        /// 执行 
        /// 例:ThreadHelper.Run(() => { }, (ex) => { });
        /// </summary>
        /// <param name="doWork">在线程中执行</param>
        /// <param name="errorAction">错误处理</param>
        public static System.Threading.Tasks.Task Run(Action doWork, LimitedTaskScheduler scheduler = null, Action<Exception> errorAction = null)
        {
            System.Threading.Tasks.Task task = System.Threading.Tasks.Task.Factory.StartNew(() =>
            {
                try
                {
                    if (doWork != null)
                    {
                        doWork();
                    }
                }
                catch (Exception ex)
                {
                    if (errorAction != null) errorAction(ex);
                    LogUtil.LogError(ex);
                }
            });
            return task;
        }

        /// <summary>
        /// 封装Dispatcher.BeginInvoke 
        /// 例:ThreadHelper.BeginInvoke(this.Dispatcher, () => { }, (ex) => { });
        /// </summary>
        /// <param name="errorAction">错误处理</param>
        public static void BeginInvoke(Dispatcher dispatcher, Action action, Action<Exception> errorAction = null)
        {
            dispatcher.InvokeAsync(new Action(() =>
            {
                try
                {
                    DateTime dt = DateTime.Now;
                    action();
                    double d = DateTime.Now.Subtract(dt).TotalSeconds;
                    if (d > 0.01) LogUtil.Log("ThreadHelper.BeginInvoke UI耗时:" + d + "秒 " + action.Target.ToString());
                }
                catch (Exception ex)
                {
                    if (errorAction != null) errorAction(ex);
                    LogUtil.LogError(ex);
                }
            }), DispatcherPriority.Background);
        }
    }
}

测试方法:

private void Test23()
{
    //变量定义
    DateTime dt = DateTime.Now;
    Random rnd = new Random();
    int taskCount = 1000;
    LimitedTaskScheduler scheduler = new LimitedTaskScheduler();

    //生成测试数据
    BlockingCollection<double> _data = new BlockingCollection<double>();
    for (int i = 0; i < taskCount; i++)
    {
        _data.Add(rnd.NextDouble());
    }

    //数据计算
    Thread thread = new Thread(new ThreadStart(() =>
    {
        dt = DateTime.Now;
        for (int i = 0; i < taskCount; i++)
        {
            ThreadHelper.Run(() =>
            {
                Thread.Sleep(50);
                double a;
                if (_data.TryTake(out a))
                {
                    double r = Math.PI * a;
                }
            }, scheduler);
        }
        double d = DateTime.Now.Subtract(dt).TotalSeconds;

        this.BeginInvoke(new Action(() =>
        {
            textBox1.Text += "调用" + taskCount + "次ThreadHelper.Run耗时:" + d.ToString() + "秒\r\n";
        }));
    }));
    thread.IsBackground = true;
    thread.Start();

    //数据计算耗时
    Thread thread2 = new Thread(new ThreadStart(() =>
    {
        while (_data.Count > 0)
        {
            Thread.Sleep(1);
        }
        double d = DateTime.Now.Subtract(dt).TotalSeconds;

        this.BeginInvoke(new Action(() =>
        {
            textBox1.Text += "数据计算结束,耗时:" + d.ToString() + "秒\r\n";
        }));
    }));
    thread2.IsBackground = true;
    thread2.Start();

    scheduler.Dispose();
}

private LimitedTaskScheduler _scheduler = new LimitedTaskScheduler();
private void Test24()
{
    //点击按钮耗时
    DateTime dt = DateTime.Now;
    ThreadHelper.Run(() =>
    {
        double d = DateTime.Now.Subtract(dt).TotalSeconds;
        this.BeginInvoke(new Action(() =>
        {
            textBox1.Text += "点击按钮耗时:" + d.ToString() + "秒\r\n";
        }));
    }, _scheduler);
}

事件方法:

private void button1_Click(object sender, EventArgs e)
{
    Test23();
}

private void button2_Click(object sender, EventArgs e)
{
    Test24();
}

测试操作步骤:

依次点击3次button1和1次button2

使用Run测试结果:

 

 使用Run2测试结果:

 

结论:使用Run,点击button2时,卡了好几秒才出来结果,而使用Run2,点击button2时,立即显示结果,button2的操作本身应该耗时极少。

现实意义:当一批耗时任务无脑使用Task.Factory.StartNew时,另一个使用Task.Factory.StartNew的任务就无法及时响应了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C#中的多线程任务(Task)是一种用于并行和异步编程的重要机制。它允许我们在应用程序中创建并发任务,从而提高性能和响应性。 在C#中,我们可以使用Task类来创建和管理多线程任务。以下是使用Task进行多线程编程的一般步骤: 1. 创建一个Task对象:我们可以使用Task类的静态方法来创建一个任务。例如,可以使用Task.Run方法创建一个简单的任务。示例代码如下: ```csharp Task task = Task.Run(() => { // 在此处执行任务操作 }); ``` 2. 定义任务操作:在创建任务时,我们通常需要定义要在任务中执行的操作。可以使用lambda表达式或方法来指定任务操作。示例代码如下: ```csharp Task task = Task.Run(() => { // 在此处执行任务操作 }); ``` 3. 等待任务完成:如果需要等待任务完成,可以使用Task类的Wait方法或await关键字。这样可以确保在继续执行后续代码之前,任务已经完成。示例代码如下: ```csharp Task task = Task.Run(() => { // 在此处执行任务操作 }); task.Wait(); // 等待任务完成 // 或者使用 await 关键字: await task; ``` 4. 处理任务结果:如果任务有返回值,我们可以使用Task<T>泛型类来创建带返回值的任务,并通过Result属性获取任务的结果。示例代码如下: ```csharp Task<int> task = Task.Run(() => { // 在此处执行任务操作并返回结果 return 42; }); int result = task.Result; // 获取任务的结果 ``` 总结起来,使用C#Task类可以方便地实现多线程编程。我们可以创建、定义和等待任务,并处理任务的结果。这样可以实现并行执行任务,提高应用程序的性能和响应性。 提供了一个基于C#开发的工具类库(MSCL超级工具类库),其中包括了很多常用工具类的封装。虽然它没有提到Task类,但我们可以借助C#的多线程编程机制来实现并发任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忧郁的蛋~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值