//--------------------------------------------------------------------------
//
// Copyright (c) BUSHUOSX. All rights reserved.
//
// File: AsyncTaskManager.cs
//
// Version:1.1.0.6
//
// Datetime:20170813
//
//-------------------------------------------------------------------------- using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks; namespace BUSHUOSX
{
class AsyncTaskManager
{
/// <summary>
/// 缓存的任务队列
/// </summary>
readonly Queue<Task> _taskQueue = new Queue<Task>(); /// <summary>
/// 工作锁,保护_taskQueue
/// </summary>
SpinLock _workLock; /// <summary>
/// 工作信号,与MaxConcurrencyLevel控制并行量
/// </summary>
SemaphoreSlim _workSemaphore; /// <summary>
/// 工作线程取消标志
/// </summary>
CancellationTokenSource _ctsCancel;
/// <summary>
/// 工作器每次启动的工作时限
/// </summary>
int _timeoutMillisecond;
/// <summary>
/// 工作线程
/// </summary>
Task _worker; /// <summary>
/// 工作器状态
/// </summary>
private bool IsWorking { get; set; } /// <summary>
/// 任务最大并发量
/// </summary>
public int MaxConcurrencyLevel { get; } /// <summary>
/// 内部工作器将在队列中有任务时自动启动。否则由Start方法启动。
/// </summary>
public bool AutoRunWorker { get; } /// <summary>
/// 队列中的任一任务完成时,都将调用
/// </summary>
private Action<Task> _callbackOnAnyTaskComplited; /// <summary>
/// 控制异步任务的并发量。
/// 注意:只能严格控制stauts为Created的任务
/// </summary>
/// <param name="maxConcurrencyLevel">最大并发数。小于等于0时设置为int.MaxValue</param>
/// <param name="callbackOnAnyTaskComplited">不为null时,队列中的任一任务完成后都将传递给此回调方法</param>
/// <param name="autoRunWorker">指示内部工作器是在内部队列排入任务时自动启动,还是由Start方法启动。</param>
/// <param name="timeout">调度完所有任务的时限。小于等于0时不设置超时</param>
public AsyncTaskManager(int maxConcurrencyLevel, Action<Task> callbackOnAnyTaskComplited = null, bool autoRunWorker = true, int timeoutMillisecond = )
{
_callbackOnAnyTaskComplited = callbackOnAnyTaskComplited;
AutoRunWorker = autoRunWorker;
MaxConcurrencyLevel = maxConcurrencyLevel <= ? int.MaxValue : maxConcurrencyLevel;
_timeoutMillisecond = timeoutMillisecond <= ? : timeoutMillisecond;
} /// <summary>
/// 排入一个任务到内部队列,该队列中的任务将被依次调用。
/// </summary>
/// <param name="task">要排队的任务。注意:只能严格控制stauts为Created的任务</param>
/// <param name="callbackOnTaskComplited">task任务完成时回调。如果所有任务使用同样的回调方法,建议使用构造函数中的callbackOnAnyTaskComplited</param>
public void QueueTask(Task task, Action<Task> callbackOnTaskComplited = null)
{
if (task == null) return;
if (null == callbackOnTaskComplited)
{
EnqueueTask(task);
}
else
{
EnqueueTask(task.ContinueWith(callbackOnTaskComplited));
}
if (AutoRunWorker)
{
notifyStartWork();
}
} /// <summary>
/// 枚举任务到内部队列,该队列中的任务将被依次调用。
/// </summary>
/// <param name="tasks">要排队的任务。注意:只能严格控制stauts为Created的任务</param>
/// <param name="callbackOnTaskComplited">tasks中的每个任务完成时回调</param>
public void QueueTask(IEnumerable<Task> tasks, Action<Task> callbackOnTaskComplited = null)
{
foreach (var item in tasks)
{
if (item == null) break;
if (null == callbackOnTaskComplited)
{
EnqueueTask(item);
}
else
{
EnqueueTask(item.ContinueWith(callbackOnTaskComplited));
}
}
if (AutoRunWorker)
{
notifyStartWork();
}
} /// <summary>
/// 返回此刻队列中的任务。
/// </summary>
/// <returns></returns>
public Task[] GetQueueTask()
{
bool gotlock = false;
try
{
_workLock.Enter(ref gotlock);
if (_taskQueue.Count > )
{
return _taskQueue.ToArray();
}
else
{
return null;
}
}
finally
{
if (gotlock) _workLock.Exit();
}
} /// <summary>
/// 启动内部工作器。
/// 注意:为降低资源占用,该工作器在内部队列为空时会自动退出。
/// </summary>
public void Start()
{
notifyStartWork();
} /// <summary>
/// 阻塞线程,等待内部工作器运行结束
/// </summary>
/// <returns>RanToCompletion:所有队列任务已被调度。Canceled:手动取消或挂起了任务,或任务超时。Faulted:未知错误。</returns>
public TaskStatus WaitTaskSchdulerComplited()
{
if (_worker == null) throw new NotSupportedException("_worker is null");
try
{
_worker.Wait();
}
catch (Exception)
{
}
return _worker.Status;
} /// <summary>
/// 挂起队列中剩余的任务。稍后可以使用Continue方法继续。
/// </summary>
public void Suspend()
{
stopWorkThread(false);
} /// <summary>
/// 停止工作器,并清空内部任务队列还未调用的任务。
/// 已调用的任务还将继续运行。
/// </summary>
public void Cancel()
{
stopWorkThread(true);
} /// <summary>
/// 停止工作器
/// </summary>
/// <param name="clearTasks">true时清空内部任务队列</param>
private void stopWorkThread(bool clearTasks)
{
if (IsWorking)
{
_ctsCancel.Cancel();
if (clearTasks)
{
bool gotlock = false;
try
{
_workLock.Enter(ref gotlock);
_taskQueue.Clear();
}
finally
{
if (gotlock) _workLock.Exit();
}
}
}
} /// <summary>
/// 继续之前挂起的任务。
/// </summary>
public void Continue()
{
notifyStartWork();
} /// <summary>
/// 内部启动工作器
/// </summary>
private void notifyStartWork()
{
if (IsWorking) return; //初始化
_ctsCancel = new CancellationTokenSource();
if (_timeoutMillisecond > )
{
_ctsCancel.CancelAfter(_timeoutMillisecond);
}
_workLock = new SpinLock();
_workSemaphore = new SemaphoreSlim(MaxConcurrencyLevel, MaxConcurrencyLevel); _worker = Task.Run(new Action(workerThread), _ctsCancel.Token);
} /// <summary>
/// 任一任务完成时调用
/// </summary>
/// <param name="task"></param>
private void anyTaskComplited(Task task)
{
_workSemaphore.Release();
//todo task
_callbackOnAnyTaskComplited?.Invoke(task);
//Debug.WriteLine("完成任务{0}:{1}", task.Id, task.Status.ToString());
} /// <summary>
/// 工作器线程执行方法。只应存在一个。
/// </summary>
private void workerThread()
{
IsWorking = true;
Debug.WriteLine("工作线程启动……");
try
{
Task tmp = null;
while (true)
{
#if DEBUG
//不恰当的操作,只为屏蔽调试时错误
//会导致_worker状态为RanToCompletion
try
{
_workSemaphore.Wait(_ctsCancel.Token);
}
catch (OperationCanceledException)
{
//_ctsCancel.Token.ThrowIfCancellationRequested();
return;
}
#else
_workSemaphore.Wait(_ctsCancel.Token); //传递取消状态
_ctsCancel.Token.ThrowIfCancellationRequested();
#endif tmp = DequeueTask();
if (tmp != null)
{
if (tmp.Status == TaskStatus.Created)
{
tmp.Start();
}
tmp.ContinueWith(anyTaskComplited);
}
else
{
if (_taskQueue.Count == )
{
Debug.WriteLine("workerAsync:taskQueue is empty");
break;
}
}
}
}
finally
{
//notifyEndWork();
IsWorking = false;
Debug.WriteLine("工作线程结束……");
}
} /// <summary>
/// 排入任务,期望线程安全
/// </summary>
/// <param name="task"></param>
private void EnqueueTask(Task task)
{
bool gotlock = false;
try
{
_workLock.Enter(ref gotlock);
_taskQueue.Enqueue(task);
}
finally
{
if (gotlock) _workLock.Exit();
} } /// <summary>
/// 弹出任务,期望线程安全
/// </summary>
/// <returns></returns>
private Task DequeueTask()
{
bool gotlock = false;
try
{
_workLock.Enter(ref gotlock);
if (_taskQueue.Count > )
{
return _taskQueue.Dequeue();
}
else
{
return null;
}
}
finally
{
if (gotlock) _workLock.Exit();
}
}
}
}

并发任务管理器AsyncTaskManager的更多相关文章

  1. 如何配置IIS处理多并发请求及存在的问题

    很多时候多线程能快速高效独立的计算数据,应用比较多. 但今天遇到的多进程下的问题更是让人觉得复杂 多进程下static变量都要失效,就目前的平台和产品static使用是很多的,各种session.ca ...

  2. mmysql-最大链接数和最大并发数的区别

    关于连接数和并发数的设置(针对Innodb引擎) 对于机器本身来说,进程数是说机器正在运行的进程数量,调出任务管理器就可以看到.连接数是指进程接收和发送数据的连接ip的数量.并发数是指进程同时发送数据 ...

  3. Visual Studio并发Qpar优化效果

    IOCP客户端的connect线程FOR循环中添加强制并行,1万/S并发connect+send+recv+close,任务管理器使用从60%降到20%. Visual Studio性能监控CPU使用 ...

  4. IIS处理并发请求时出现的问题及解决

    一个ASP.NET项目在部署到生产环境时,当用户并发量达到200左右时,IIS出现了明显的请求排队现象,发送的请求都进入等待,无法及时响 应,系统基本处于不可用状态.因经验不足,花了很多时间精力解决这 ...

  5. java线程与并发(一)

    有好几个月没写博客了,各种破事儿忙完,决定继续写博客,恰好最近想了解下有关Java并发的一些知识,所以就准备这一段时间,用零碎的时间多记录一点有关并发的知识.希望这次能一直坚持下去. 想了解并发,必须 ...

  6. Java并发编程:如何创建线程?

    Java并发编程:如何创建线程? 在前面一篇文章中已经讲述了在进程和线程的由来,今天就来讲一下在Java中如何创建线程,让线程去执行一个子任务.下面先讲述一下Java中的应用程序和进程相关的概念知识, ...

  7. Java多线程中的进程,线程,并行,并发

    2:什么是进程? 通过任务管理器我们就看到了进程的存在. 而通过观察,我们发现只有运行的程序才会出现进程. 进程:就是正在运行的程序. 进程是系统进行资源分配和调用的独立单位.每一个进程都有它自己的内 ...

  8. Java并发编程:线程和进程的创建(转)

    Java并发编程:如何创建线程? 在前面一篇文章中已经讲述了在进程和线程的由来,今天就来讲一下在Java中如何创建线程,让线程去执行一个子任务.下面先讲述一下Java中的应用程序和进程相关的概念知识, ...

  9. python并发编程之多进程一

    一,什么是进程 进程是操作系统结构的基础:是一个正在执行的程序:计算机中正在运行的程序实例:可以分配给处理器并由处理器执行的一个实体: 二,进程与程序的区别 进程即运行中的程序,从中即可知,进程是在运 ...

随机推荐

  1. Java导出Highcharts需要的3个外部jar包

    xerces batik fop 这三个JAR包. 绝对可用.自本用过. 如果两个项目在同一个TOMCAT下并且同时用到xerces.jar,需要前这个外放在TOMCAT下的lib目录下.其他的容器中 ...

  2. AtCoder Grand Contest

    一句话题解 QwQ主要是因为这篇文章写的有点长……有时候要找某一个题可能不是很好找,所以写了这个东西. 具体的题意.题解和代码可以再往下翻._(:з」∠)_ AGC 001 C:枚举中点/中边. D: ...

  3. python 中if-else的多种简洁的写法

    因写多了判断语句,看着短短的代码却占据来好几行,于是便搜下if-else简洁的写法,结果也是发现新大陆 4种: 第1种:__就是普通写法 a, b, c = 1, 2, 3 if a>b: c ...

  4. shrio的rememberMe不起作用

    在移植项目.每次重启服务器需要登录.比较麻烦.于是研究下shrio的功能. rememberMe大概可以满足我的需求.但是跟着网上配置了.不起作用...... 于是乎查看源代码拉.java的好处... ...

  5. peripheralStateNotificationCB

    /********************************************************************* * @fn peripheralStateNotifica ...

  6. 时钟晶振32.768KHz为什么是15分频?

    实时时钟晶振为什么选择是32768Hz的晶振,在百度上搜索的话大部分的答案都是说2的15次方是32768,使用这个频率的晶振,人们可以很容易的通过分频电路得到1Hz的计时脉冲.但是话有说回来了,2的整 ...

  7. php分页方法

    $page_on=15;//定义每页显示数 $pageNum=$_GET['pageNum']; //当前页数 $result = mysql_query("SELECT * FROM ne ...

  8. 关于SQL优化这些你了解吗?

    目录树 背景 优化点 前提必备知识 优化之一 - 从数据库设计方面考虑 优化之二 - 从SQL语句优化方面考虑 优化之三 - 读写分离与分库分表 背景 在当今这个互联网的时代无非要解决两大难题,其一是 ...

  9. Notes 20180308 : 语句

    在讲解流程控制语句之前,我们先来说一下语句的问题.Java中的语句分为声明和赋值语句,条件和循环语句,调用和返回语句:我们之所以每两个放在一起是有深意的,我们大致将语句分为这三块,并以此为纲来说一下, ...

  10. Ajax请求(415 Unsupported Media Type)

    Unsupported media type-415(不支持的媒体类型) 该错误类型是后台接收参数为json类型的,然而ajax提交的类型不对,如下: 异常代码: $.ajax({ url: api ...