我同意其他人TPL数据流听起来这是很好的解决方案。
要限制处理,你可以创建一个TransformBlock
实际上并没有以任何方式转换数据,它只是延缓它,如果它以前的数据后立即赶到:
static IPropagatorBlock<T, T> CreateDelayBlock<T>(TimeSpan delay)
{
DateTime lastItem = DateTime.MinValue;
return new TransformBlock<T, T>(
async x =>
{
var waitTime = lastItem + delay - DateTime.UtcNow;
if (waitTime > TimeSpan.Zero)
await Task.Delay(waitTime);
lastItem = DateTime.UtcNow;
return x;
},
new ExecutionDataflowBlockOptions { BoundedCapacity = 1 });
}
然后创建一个方法产生的数据(从0开始的整数例子):
static async Task Producer(ITargetBlock<int> target)
{
int i = 0;
while (await target.SendAsync(i))
i++;
}
它的异步写入,因此,如果目标块是不能够马上处理的项目,它会等待。
然后写一个消费者方法:
static void Consumer(int i)
{
Console.WriteLine(i);
}
最后,连在一起这一切,并启动它:
var delayBlock = CreateDelayBlock<int>(TimeSpan.FromMilliseconds(500));
var consumerBlock = new ActionBlock<int>(
(Action<int>)Consumer,
new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded });
delayBlock.LinkTo(consumerBlock, new DataflowLinkOptions { PropagateCompletion = true });
Task.WaitAll(Producer(delayBlock), consumerBlock.Completion);
这里,delayBlock
将接受最多一个每500毫秒项和方法可以并行运行多次。要完成处理,请拨打delayBlock.Complete()
。
如果你想为你的#2添加一些缓存,你可以创建另一个TransformBlock
做那里的工作,并将其链接到其他块。
我认为至少#2是不可能做到与TaskScheduler,因为它处理“任务”,并且没有办法从中获取这些信息。 – svick 2012-03-20 22:25:43
您是否对使用C#5/.Net 4.5的解决方案感兴趣? – svick 2012-03-20 22:26:10
@svick绝对,我有幸被允许使用c#5 – Fen 2012-03-20 22:32:36