按顺序处理异步调用

时间:2015-01-05 11:46:10

标签: c# .net azure asynchronous task-parallel-library

我正在为Azure Table Storage做一堆或asynchronous calls。由于显而易见的原因,这些记录的插入顺序与它们被调用的顺序不同。

我计划引入ConcurrentQueue以确保顺序。以下作为POC编写的示例代码似乎达到了预期的结果。

  

我想知道这是我可以确保异步调用的最佳方式   将按顺序完成?

public class ProductService
{
    ConcurrentQueue<string> ordersQueue = new ConcurrentQueue<string>();
    //Place make calls here
    public void PlaceOrder()
    {
        Task.Run(() =>
        {
            Parallel.For(0, 100, (i) =>
            {
                string item = "Product " + i;
                ordersQueue.Enqueue(item);
                Console.WriteLine("Placed Order: " + item);
                Task.Delay(2000).Wait();
            });

        });

    }

    //Process calls in sequence, I am hoping concurrentQueue will be consistent.
    public void Deliver()
    {
        Task.Run(() =>
        {
            while(true)
            {
                string productId;
                ordersQueue.TryDequeue(out productId);
                if (!string.IsNullOrEmpty(productId))
                {
                    Console.WriteLine("Delivered: " + productId);
                }
            }
        });
    }
}

2 个答案:

答案 0 :(得分:4)

如果你想以异步和顺序的方式处理记录,这听起来非常适合TPL Dataflow的ActionBlock。只需创建一个包含要执行的操作的块,并将记录发布到该块。它支持async个动作并保持秩序:

var block = new ActionBlock<Product>(async product =>
{
    await product.ExecuteAsync();
});

block.Post(new Product());

如果需要,它还支持并行处理和有限容量处理。

答案 1 :(得分:1)

尝试使用Microsoft的Reactive Framework。

这对我有用:

IObservable<Task<string>> query =
    from i in Observable.Range(0, 100, Scheduler.Default)
    let item = "Product " + i
    select AzureAsyncCall(item);

query
    .Subscribe(async x =>
    {
        var result = await x;
        /* do something with result */
    });

我使用的AzureAsyncCall来电签名是public Task<string> AzureAsyncCall(string x)

我放弃了一堆Console.WriteLine(Thread.CurrentThread.ManagedThreadId);次调用,以确保我在测试代码中获得了正确的异步行为。它运作良好。

所有调用都是异步的,并且一个接一个地序列化。