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 = ;
private int _timeOut = Timeout.Infinite;
private Task _tempTask;
#endregion #region 构造函数
public LimitedTaskScheduler(int threadCount = )
{
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 = ; 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, -, -);
}
}
#endregion #region 创建线程池
/// <summary>
/// 创建线程池
/// </summary>
private void CreateThreads(int? threadCount = null)
{
if (threadCount != null) _threadCount = threadCount.Value;
_timeOut = Timeout.Infinite; for (int i = ; 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 = ;
LimitedTaskScheduler scheduler = new LimitedTaskScheduler(); //生成测试数据
BlockingCollection<double> _data = new BlockingCollection<double>();
for (int i = ; i < taskCount; i++)
{
_data.Add(rnd.NextDouble());
} //数据计算
Thread thread = new Thread(new ThreadStart(() =>
{
dt = DateTime.Now;
for (int i = ; i < taskCount; i++)
{
ThreadHelper.Run(() =>
{
Thread.Sleep();
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 > )
{
Thread.Sleep();
}
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的任务就无法及时响应了。

C# Task 多任务 限制Task并发数量的更多相关文章

  1. C# 多任务之 Task

    Task 是什么 ? Task 是一个类, 它表示一个操作不返回一个值,通常以异步方式执行. Task 对象是一个的中心思想 基于任务的异步模式 首次引入.NET Framework 4 中. 继承层 ...

  2. C# 执行固定个数任务自行控制进入线程池的线程数量,多任务同时但是并发数据限定

    思路来源:http://bbs.csdn.NET/topics/390819824,引用该页面某网友提供的方法. 题目:我现在有100个任务,需要多线程去完成,但是要限定同时并发数量不能超过5个. 原 ...

  3. async和enterproxy控制并发数量

    聊聊并发与并行 并发我们经常提及之,不管是web server,app并发无处不在,操作系统中,指一个时间段中几个程序处于已经启动运行到完毕之间,且这几个程序都是在同一处理机上运行,并且任一个时间点只 ...

  4. Spring的任务调度@Scheduled注解——task:scheduler和task:executor的解析

    原文地址: https://blog.csdn.net/yx0628/article/details/80873774 一个简单的Spring定时任务的 demo,全部代码见下载地址:https:// ...

  5. 【C# Task】理解Task中的ConfigureAwait配置同步上下文

    原文:https://devblogs.microsoft.com/dotnet/configureawait-faq/ 作者:Stephen 翻译:xiaoxiaotank 静下心来,你一定会有收获 ...

  6. Task.Run Vs Task.Factory.StartNew

    在.Net 4中,Task.Factory.StartNew是启动一个新Task的首选方法.它有很多重载方法,使它在具体使用当中可以非常灵活,通过设置可选参数,可以传递任意状态,取消任务继续执行,甚至 ...

  7. Task.Run Vs Task.Factory.StartNew z

    在.Net 4中,Task.Factory.StartNew是启动一个新Task的首选方法.它有很多重载方法,使它在具体使用当中可以非常灵活,通过设置可选参数,可以传递任意状态,取消任务继续执行,甚至 ...

  8. MapReduce作业的map task和reduce task调度参数

    MapReduce作业可以细分为map task和reduce task,而MRAppMaster又将map task和reduce task分为四种状态: 1.pending:刚启动但尚未向reso ...

  9. C# Task的使用---Task的启动

    .NET 4.0包含的新名称空间System.Threading.Tasks,它包含的类抽象出了线程功能.任务表示应完成的某个单元的工作.这个单元的工作可以在单独的线程中运行,也可以以同步的方式启动一 ...

随机推荐

  1. 第四章 开始Unity Shader学习之旅(2)

    目录 1. 强大的援手:Unity提供的内置文件和变量 1.1 内置的包含文件 1.2 内置的变量 2. Unity提供的Cg/HLSL语义 2.1 什么是语义 2.2 Unity支持的语义 2.3 ...

  2. vue-socket.io使用教程与踩坑记录

    全手打原创,转载请标明出处:https://www.cnblogs.com/dreamsqin/p/12018866.html,多谢,=.=~ (如果对你有帮助的话请帮我点个赞啦) 请先允许我狠狠吐个 ...

  3. docker tomcat镜像部署springbootwar包

    springboot打war包 1.在pom文件中增加插件 <build> <finalName>xx</finalName> <plugins> &l ...

  4. luogu P1807 最长路_NOI导刊2010提高(07)

    题目描述 设G为有n个顶点的有向无环图,G中各顶点的编号为1到n,且当为G中的一条边时有i < j.设w(i,j)为边的长度,请设计算法,计算图G中<1,n>间的最长路径. 输入格式 ...

  5. SI522和RC522/ZS3801/FM17520的区别

    小编最近在测试一颗新的芯片,是国内知名厂家中科微研发的,主打超低功耗的厂家. 经过测试和比较小编发现 相对于MFRC522,SI522可以完全替换,不需要做任何更改,同时接受模式下功耗低10mA左右, ...

  6. unix环境高级编程中的err_quit,err_sys用到的知识点

    unix环境高级编程中的err_quit,err_sys 环境 os CentOS release 6.7 (Final) gcc 4.4.7 c语言预备知识 标准输入输出文件 在linux系统中一切 ...

  7. 200G网盘资源分享

    今日偶得大量网盘资源,遂写一博文以分享! 来源:HACK学习呀,微信公众号:HACK学习呀 文件名 链接 提取密码 2015cracer入侵入门到精通视频教程 点我查看 trf3 一笔√带过入侵教程 ...

  8. 【JS】403- JavaScript 工具函数大全(新)

    前言 一线大厂笔试题灵感来源 目录: 第一部分:数组 第二部分:函数 第三部分:字符串 第四部分:对象 第五部分:数字 第六部分:浏览器操作及其它 筛选自以下两篇文章: <127 Helpful ...

  9. Webpack基础知识总结

    本文将从多个方面回顾下自己了解的Webpack知识,包括常见的配置项,前端搭建的一些方法和项目实际优化方法,有错误的地方还请指出并多多包涵. 一.关于Webpack 1.概念 本质上,webpack ...

  10. Java中final修饰的数据

    目录 Java中final修饰的数据 有初始值的final域 final+基本数据类型 final+引用数据类型 final与static final 空白final域 final修饰的参数 基本数据 ...