我有一个场景,在这个场景中,我正在执行一些Actor-Model类型的消息等号,其中我希望有一个方法将一个任务或委托插入到一个队列(可能是新的ConcurrentQueue)中,等待其他进程处理队列,执行任务,然后返回结果,最好没有锁定。可以同步和异步地调用该方法。只有一个排队的操作可以同时运行。
我无法思考如何以一种有点表现力的方式来完成这一任务,请帮助:)
编辑
这里有一个尝试,有人发现这种方法有任何问题(排除异常处理)?而且,我可以想象,与简单的锁定相比,这有相当大的开销,并且与例如使用异步委托相比,它是如何比较的?
public partial class Form1 : Form
{
private BlockingCollection<Task<int>> blockingCollection = new BlockingCollection<Task<int>>(new ConcurrentQueue<Task<int>>());
private int i = 0;
public Form1() {
InitializeComponent();
Task.Factory.StartNew(() =>
{
foreach (var task in blockingCollection.GetConsumingEnumerable()) {
task.Start();
task.Wait();
}
});
}
public int Queue() {
var task = new Task<int>(new Func<int>(DoSomething));
this.blockingCollection.Add(task);
task.Wait();
return task.Result;
}
public int DoSomething() {
return Interlocked.Increment(ref this.i);
}
private void button1_Click(object sender, EventArgs e) {
Task.Factory.StartNew(() => Console.Write(this.Queue()));
}
}发布于 2011-04-08 07:58:44
TPL应该为您做这件事--只需在您的Task<T>上调用Task<T>--但是,在不阻塞的情况下,无法做到这一点;根据定义,在您的场景中,这正是您想要做的。阻塞可以通过lock实现,但也有其他方法-- TPL隐藏了这一点。就个人而言,在类似的场景中,我使用一个自定义队列和一个可以用来锁定的小型对象池(从未暴露在包装器之外)来执行此操作。
您可能还需要查看C# 5异步/等待的内容。
但是请注意:如果您在等待时没有做任何有用的事情,那么最好在当前线程上直接运行该代码--除非问题是线程绑定的,例如多路复用器。如果您感兴趣,今天晚些时候(或周末),我打算发布堆栈溢出用于与redis对话的复用器,它(至少在同步模式下)有您所描述的问题。
顺便提一句,如果您可以使用回调(来自另一个线程),而不必等待完成,那么总体上来说,这是更有效的。但并不是每一种情况都适合。
https://stackoverflow.com/questions/5591833
复制相似问题