具有排队的异步/同步并发调用

时间:2011-04-08 07:23:50

标签: c# concurrency asynchronous task

我有一个场景,我正在做一些Actor-Model类型的消息传递,我想要一个方法将一个Task或委托插入一个队列(可能是新的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()));
    }


  }

1 个答案:

答案 0 :(得分:0)

TPL应该为您做到这一点 - 只需在Wait()上拨打Task<T> - 然而,没有阻止就无法做到这一点;根据定义,在你想要做的的场景中。阻止可能通过lock实现,但还有其他方法 - TPL隐藏了这一点。就个人而言,在类似的场景中,我使用自定义队列和可用于锁定的对象的迷你池(从未暴露在包装器外部)。

您可能还想查看C#5 async / await stuff。

但请注意:如果您在等待时不打算做任何有用的事情,那么您也可以直接在当前线程上运行该代码 - 除非问题是线程限制的,例如多路复用器。如果您感兴趣,今天晚些时候(或周末)我打算释放stackoverflow用来与redis通信的多路复用器,它(至少在同步模式下)具有您描述的问题。

作为旁注;如果您可以使用回调(来自其他线程),而不必在完成时等待,那么整体效率会更高。但它并不适合所有情况。