转:Task任务调度实现生产者消费者模式
我们经常会遇到生产者消费者模式,比如前端各种UI操作事件触发后台逻辑等。在这种典型的应用场景中,我们可能会有4个业务处理逻辑(下文以P代表生产者,C代表消费者):
1. FIFO(先进先出)
P产生1,2,3,4,5,6,3,2
C处理顺序应为1,2,3,4,5,6,3,2
2.LIFO(后进先出)
P产生1,2,3,4,5,6,3,2
C处理顺序应为2,3,6,5,4,3,2,1
3.Dynamic FIFO(我定义为:去掉相同数据的FIFO, 如果产生的数据队列里已经有相同数据,后进的数据优先级高)
P产生1,2,3,4,5,6,3,2
C处理顺序为1,4,5,6,3,2
4.Dynamic LIFO(我定义为:去掉相同数据的LIFO, 如果产生的数据栈里已经有相同数据,后进的数据优先级高)
P产生1,2,3,4,5,6,3,2
C处理顺序为2,3,6,5,4,1
1,2情况为基本处理逻辑,3,4可能和我们实际场景有关系(包括:判断相同的逻辑可能不同、已存在和后续数据哪个优先级高)
C#中有个Task类进行异步操作,我们可以通过TaskScheduler类进行任务调度,实现上述的4种基本场景。
定义上述4种场景的通用接口以及其遍历类
public interface IScheduler : IEnumerable<Task >
{
void Add (Task t);
void Remove (Task t);
int Count { get; }
Task this [int index] { get; set ; }
}
public class SchedulerEnumerator : IEnumerator< Task>
{
private IScheduler _collection;
private int _currentIndex;
private Task _currentTask;
public SchedulerEnumerator (IScheduler collection)
{
_collection = collection ;
_currentIndex = -1;
_currentTask = default (Task);
}
public bool MoveNext()
{
//Avoids going beyond the end of the collection.
if (++_currentIndex >= _collection. Count)
{
return false ;
}
else
{
// Set current box to next item in collection.
_currentTask = _collection [_currentIndex];
}
return true ;
}
public void Reset() { _currentIndex = -1; }
void IDisposable .Dispose() { }
public Task Current
{
get { return _currentTask; }
}
object IEnumerator .Current
{
get { return Current; }
}
}
实现我们自己的任务调度类模板,可以通过T传递我们想要的队列类型
public class TaskSchedulerBase <T> : TaskScheduler
where T : IScheduler , new ()
{
private Thread _processThread;
private readonly object _lock = new object ();
public TaskSchedulerBase()
{
_processThread = new Thread (this.Process);
}
private void Process()
{
lock (_lock)
{
var tasks = GetScheduledTasks();
if (null != tasks)
{
foreach (var t in tasks)
{
TryExecuteTask(t);
TryDequeue(t);
}
}
}
}
protected override void QueueTask( Task task)
{
lock (_lock)
{
Scheduler.Add(task);
if (_processThread.ThreadState.Equals(ThreadState .Stopped))
{
_processThread = new Thread (Process);
}
if (!_processThread.IsAlive
&& !_processThread.ThreadState.Equals( ThreadState.Running))
{
try
{
_processThread.Start();
}
catch (System.Exception )
{
if (!_processThread.ThreadState.Equals(ThreadState .Running))
{
_processThread = new Thread (Process);
_processThread.Start();
}
}
}
}
}
protected override bool TryDequeue( Task task)
{
Scheduler.Remove(task);
return true ;
}
protected override IEnumerable< Task> GetScheduledTasks()
{
return Scheduler.ToArray();
}
protected override bool TryExecuteTaskInline( Task task, bool taskWasPreviouslyQueued)
{
if (taskWasPreviouslyQueued)
{
if (TryDequeue(task))
{
return base .TryExecuteTask(task);
}
else
{
return false ;
}
}
else
{
return base .TryExecuteTask(task);
}
}
private readonly T _scheduler = new T();
public T Scheduler
{
get
{
return _scheduler;
}
}
}
实现4种队列
1.FIFO
public class QueueScheduler : IScheduler
{
protected Queue <Task> _queue;
public QueueScheduler ()
{
_queue = new Queue< Task>();
}
public void Add( Task t )
{
if (!Contains (t))
{
_queue.Enqueue (t);
}
}
public void Remove( Task t )
{
_queue.Dequeue ();
}
public bool Contains( Task t )
{
bool found = false;
foreach (var task in _queue )
{
if (t .AsyncState != null && t .AsyncState. Equals(task .AsyncState))
{
found = true ;
break;
}
}
return found ;
}
public bool Contains( Task t , EqualityComparer< Task> comp )
{
throw new NotImplementedException();
}
public IEnumerator <Task> GetEnumerator()
{
return new SchedulerEnumerator( this);
}
IEnumerator IEnumerable .GetEnumerator()
{
return new SchedulerEnumerator( this);
}
public int Count
{
get { return _queue. Count; }
}
public Task this[ int index]
{
get { return (Task) _queue.ToArray ()[index]; }
set { _queue .ToArray()[index] = value; }
}
}
2.LIFO
public class StackScheduler : IScheduler
{
protected Stack <Task> _stack;
public StackScheduler ()
{
_stack = new Stack< Task>();
}
public void Add( Task t )
{
if (!Contains (t))
{
_stack.Push (t);
}
}
public void Remove( Task t )
{
_stack.Pop ();
}
public bool Contains( Task t )
{
bool found = false;
foreach (var task in _stack )
{
if (t .AsyncState != null && t .AsyncState. Equals(task .AsyncState))
{
found = true ;
break;
}
}
return found ;
}
public bool Contains( Task t , EqualityComparer< Task> comp )
{
throw new NotImplementedException();
}
public IEnumerator <Task> GetEnumerator()
{
return new SchedulerEnumerator( this);
}
IEnumerator IEnumerable .GetEnumerator()
{
return new SchedulerEnumerator( this);
}
public int Count
{
get { return _stack. Count; }
}
public Task this[ int index]
{
get { return (Task) _stack.ToArray ()[index]; }
set { _stack .ToArray()[index] = value; }
}
}
3.Dynamic FIFO
public class DynamicQueueScheduler : IScheduler
{
protected List <Task> _queue;
public DynamicQueueScheduler ()
{
_queue = new List< Task>();
}
public virtual void Add(Task t)
{
Task oldTask = null;
if (Contains (t, out oldTask ))
{
_queue.Remove (oldTask);
}
_queue.Add (t);
}
public virtual void Remove(Task t)
{
_queue.Remove (t);
}
public virtual bool Contains(Task t)
{
Task oldTask = null;
bool found = Contains( t, out oldTask);
return found ;
}
public virtual bool Contains(Task t, out Task oldTask)
{
bool found = false;
oldTask = null ;
foreach (var task in _queue )
{
if (t .AsyncState != null && t .AsyncState. Equals(task .AsyncState))
{
oldTask = task ;
found = true ;
break;
}
}
return found ;
}
public virtual bool Contains(Task t, EqualityComparer<Task > comp)
{
throw new NotImplementedException();
}
public IEnumerator <Task> GetEnumerator()
{
return new SchedulerEnumerator( this);
}
IEnumerator IEnumerable .GetEnumerator()
{
return new SchedulerEnumerator( this);
}
public int Count
{
get { return _queue. Count; }
}
public Task this[ int index]
{
get { return (Task) _queue[index]; }
set { _queue [index] = value; }
}
}
4.Dynamic LIFO
public class DynamicStackScheduler : IScheduler
{
protected List <Task> _queue;
public DynamicStackScheduler ()
{
_queue = new List< Task>();
}
public void Add( Task t )
{
Task oldTask = null;
if (Contains (t, out oldTask ))
{
_queue.Remove (oldTask);
}
_queue.Insert (0,t);
}
public void Remove( Task t )
{
_queue.Remove (t);
}
public bool Contains( Task t )
{
Task oldTask = null;
bool found = Contains( t, out oldTask);
return found ;
}
public bool Contains( Task t , out Task oldTask )
{
bool found = false;
oldTask = null ;
foreach (var task in _queue )
{
if (t .AsyncState != null && t .AsyncState. Equals(task .AsyncState))
{
oldTask = task ;
found = true ;
break;
}
}
return found ;
}
public bool Contains( Task t , EqualityComparer< Task> comp )
{
throw new NotImplementedException();
}
public IEnumerator <Task> GetEnumerator()
{
return new SchedulerEnumerator( this);
}
IEnumerator IEnumerable .GetEnumerator()
{
return new SchedulerEnumerator( this);
}
public int Count
{
get { return _queue. Count; }
}
public Task this[ int index]
{
get { return (Task) _queue[index]; }
set { _queue [index] = value; }
}
}
测试代码
class Program
{
static Queue <int> _queue = new Queue< int>();
//static TaskFactory _factory = new TaskFactory(new TaskSchedulerBase<QueueScheduler>());
//static TaskFactory _factory = new TaskFactory(new TaskSchedulerBase<StackScheduler>());
//static TaskFactory _factory = new TaskFactory(new TaskSchedulerBase<DynamicQueueScheduler>());
//static TaskFactory _factory = new TaskFactory(new TaskSchedulerBase<DynamicStackScheduler>());
static TaskFactory _factory = new TaskFactory (new TaskSchedulerBase<DynamicQueueScheduler >());
static void Main( string[] args )
{
var thread1 = new Thread(Producer );
var thread2 = new Thread(Consumer );
thread1.Start ();
thread2.Start ();
Console.ReadKey ();
}
static void Producer()
{
for (int i = 0; i < 7; i ++)
{
_queue.Enqueue (i);
}
_queue.Enqueue (3);
_queue.Enqueue (2);
}
static void Consumer()
{
while (true )
{
if (_queue .Count > 0)
{
foreach (var i in _queue )
{
_factory.StartNew ((s) =>
{
Console.Write ("{0} on thread {1} {2}\n", s,Thread.CurrentThread .ManagedThreadId,
DateTime.Now.ToLongTimeString());
}, i);
}
_queue.Clear ();
}
else
{
Thread.Sleep (1);
}
}
}
}
转:Task任务调度实现生产者消费者模式的更多相关文章
- 转:Task任务调度实现生产者消费者模式 (个人理解后文)
纯属个人愚见.欢迎加入反驳(PiDou). 1.前文大致就是,利用Queue配置的一个TaskFactory任务调度器.实现生产者消费者模式的例子..首先我就试了 第一种 FIFO(先进先出)的配置. ...
- Celery 框架学习笔记(生产者消费者模式)
生产者消费者模式 在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类.函数.线程.进程等).产生数据的模块,就形象地称为生产 ...
- python3全栈开发-多进程的守护进程、进程同步、生产者消费者模式(重点)
一.守护进程 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes a ...
- 第三节: List类型的介绍、生产者消费者模式、发布订阅模式
一. List类型基础 1.介绍 它是一个双向链表,支持左进.左出.右进.右出,所以它即可以充当队列使用,也可以充当栈使用. (1). 队列:先进先出, 可以利用List左进右出,或者右进左出(Lis ...
- Java实现多线程生产者消费者模式的两种方法
生产者消费者模式:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据.生产者生产一个,消费者消费一个,不断循环. 第一种实现方法,用BlockingQueue阻塞队 ...
- java多线程 生产者消费者模式
package de.bvb; /** * 生产者消费者模式 * 通过 wait() 和 notify() 通信方法实现 * */ public class Test1 { public static ...
- LabVIEW之生产者/消费者模式--队列操作 彭会锋
LabVIEW之生产者/消费者模式--队列操作 彭会锋 本文章主要是对学习LabVIEW之生产者/消费者模式的学习笔记,其中涉及到同步控制技术-队列.事件.状态机.生产者-消费者模式,这几种技术在在本 ...
- Lucene.net站内搜索—4、搜索引擎第一版技术储备(简单介绍Log4Net、生产者消费者模式)
目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...
- MVC异常日志生产者消费者模式记录(异常过滤器)
生产者消费者模式 定义自己的异常过滤器并注册 namespace Eco.Web.App.Models { public class MyExceptionAttribute : HandleErro ...
随机推荐
- PDO数据库抽象层
PDO的优势在于兼容性,但速度不如mysql和mysqli new PDO($dsn,$username,$passwd[,$options]) $options可以设置数据库连接属性,如: $opt ...
- jsp表格数据导出到Execl
1.关于“下载” 需要设置页面header的一个属性为:Content-Disposition: attachment; filename=下载的文件.txt 如: <a href=" ...
- jquery总结04-DOM节点操作
一般js操作节点 ①创建节点(元素文本)document.createElement innerHTML ②添加属性 setAttribute ③加入文档 appendChild 操作繁琐还有兼容性 ...
- struts(二) ---中参数传值
struts中参数传值的方式有 种: 第一种:直接通过属性来传值 第二种: 第三种:
- FROM_UNIXTIME()和UNIX_TIMESTAMP()函数的区别
Unix时间戳(Unix timestamp),是一种时间表示方式,定义为从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数. 在MySQL中如何格式化时间戳?在mysql中因为t ...
- stage3D之疑问
1.stage3D本身是建立在图形API(如DirectX.Opengl等)之上的一套API,那么在创建stage3D demo时,如何指定使用哪种图形API呢?
- css样式设计
1.行内元素(图片.文本)水平居中 通过给父元素设置 text-align:center html代码: <body> <div class="txtCenter" ...
- src与href
href是指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接,用于超链接. src是指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置:在请求src资源时会将其指向的 ...
- oracle修改序列
Oracle 序列(Sequence)主要用于生成流水号,在应用中经常会用到,特别是作为ID值,拿来做表主键使用较多. 但是,有时需要修改序列初始值(START WITH)时,有同仁使用这个语句来 ...
- DbUtils常用API的使用 方便以后查阅
package com.lizhou.Test; import java.sql.SQLException; import java.util.List; import java.util.Map; ...