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 = ;
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并发数量的更多相关文章
- C# 多任务之 Task
Task 是什么 ? Task 是一个类, 它表示一个操作不返回一个值,通常以异步方式执行. Task 对象是一个的中心思想 基于任务的异步模式 首次引入.NET Framework 4 中. 继承层 ...
- C# 执行固定个数任务自行控制进入线程池的线程数量,多任务同时但是并发数据限定
思路来源:http://bbs.csdn.NET/topics/390819824,引用该页面某网友提供的方法. 题目:我现在有100个任务,需要多线程去完成,但是要限定同时并发数量不能超过5个. 原 ...
- async和enterproxy控制并发数量
聊聊并发与并行 并发我们经常提及之,不管是web server,app并发无处不在,操作系统中,指一个时间段中几个程序处于已经启动运行到完毕之间,且这几个程序都是在同一处理机上运行,并且任一个时间点只 ...
- Spring的任务调度@Scheduled注解——task:scheduler和task:executor的解析
原文地址: https://blog.csdn.net/yx0628/article/details/80873774 一个简单的Spring定时任务的 demo,全部代码见下载地址:https:// ...
- 【C# Task】理解Task中的ConfigureAwait配置同步上下文
原文:https://devblogs.microsoft.com/dotnet/configureawait-faq/ 作者:Stephen 翻译:xiaoxiaotank 静下心来,你一定会有收获 ...
- Task.Run Vs Task.Factory.StartNew
在.Net 4中,Task.Factory.StartNew是启动一个新Task的首选方法.它有很多重载方法,使它在具体使用当中可以非常灵活,通过设置可选参数,可以传递任意状态,取消任务继续执行,甚至 ...
- Task.Run Vs Task.Factory.StartNew z
在.Net 4中,Task.Factory.StartNew是启动一个新Task的首选方法.它有很多重载方法,使它在具体使用当中可以非常灵活,通过设置可选参数,可以传递任意状态,取消任务继续执行,甚至 ...
- MapReduce作业的map task和reduce task调度参数
MapReduce作业可以细分为map task和reduce task,而MRAppMaster又将map task和reduce task分为四种状态: 1.pending:刚启动但尚未向reso ...
- C# Task的使用---Task的启动
.NET 4.0包含的新名称空间System.Threading.Tasks,它包含的类抽象出了线程功能.任务表示应完成的某个单元的工作.这个单元的工作可以在单独的线程中运行,也可以以同步的方式启动一 ...
随机推荐
- nginx部署安装
首先需要下载Nginx软件包 nginx软件官方下载地址:[nginx官方下载连接](http://www.nginx.org) 建议选择稳定的软件版本,如果练习使用当然是无所谓,随便什么版本都可以, ...
- Python文本转化语音模块大比拼,看看青铜与王者的差别!
文本转语音 如果把Python比喻成游戏中的一个英雄,你觉得它是谁?对于Dota老玩家来说,我会想到钢琴手卡尔!感觉Python和卡尔一样,除了生孩子什么都可以做的角色.日常生活中,我们会涉及到很多语 ...
- MySql数据基础之数据表操作
MySql数据库中主要利用多个数据表进行数据的存储,我们可以将数据表理解成一个Excel表格,Excel表格的第一列可以将它看为id列,主要任务是数据表中数据的唯一标识,不能重复.不能为空.如果将数据 ...
- Dapr 运用
Dapr 运用 前置条件 Docker Win10 Dapr 部署 本文将采用本地部署的方式. 安装 Dapr CLI 打开 Windows PowerShell 或 cmd ,运行以下命令以安装 D ...
- react-native中TextInput在ios平台下不能输入中文
目录 1. github上相关资料 2.需要满足defultValue和value属性 react-native 0.55.4版本,发现TextInput 在iOS平台上无法输入中文的问题. 1. g ...
- 学习go第一天-编写第一个go程序
开发环境构建 GOPATH 在1.8版本前必须设置这个环境变量 1.8以及更高版本如果没有设置,则使用默认值在Mac上GOPATH可以通过修改 -/.bash_profile来设置 程序基本结构 pa ...
- NIM游戏,NIM游戏变形,威佐夫博弈以及巴什博奕总结
NIM游戏,NIM游戏变形,威佐夫博弈以及巴什博奕总结 经典NIM游戏: 一共有N堆石子,编号1..n,第i堆中有个a[i]个石子. 每一次操作Alice和Bob可以从任意一堆石子中取出任意数量的石子 ...
- git避免每次输入密码
生成公匙 在仓库所在目录输入 ssh-keygen -t rsa -C "yourname@sina.com" 其中yourname@sina.com是注册邮箱.可以在%HOME% ...
- linux-iptables增、删、改、保存
iptables基础: iptables的5条链分别是: prerouting 路由前 input 发到本机进程的报文 ouput 本机某进程发出的报文 forword 转发 postrouting ...
- 为什么有ASP.NET
最近读了一些文章,总结一下: 在1999年,当时微软的windows系统运行的所有的应用程序都是有组件对象模型为根本基础开发的,用VB来处理数据访问和复杂的用户界面,缺点是不能使用函数指针,因为当时的 ...