结合异步方法的结果并同步返回

时间:2015-05-25 14:37:26

标签: c# azure asynchronous async-await

我读了许多人们遇到类似问题的帖子,但他们似乎做出了不适用的假设,或者他们的代码根本不适用于我。我需要合并异步方法的结果。 我想要的唯一的async是结果的组合。由于Azure Service Bus一次只允许我抓取256条消息,我想发送多个请求以获得几个批次立即将其列入一个列表。

  

似乎有一个假设,如果你正在调用异步   您希望在工作完成时返回给调用者的方法   (即:一些长期运行的任务)。但是,我根本不想要那个。一世   想要等待任务完成,然后采取我的组合列表   并将其归还。

首先,我不想用异步标记我的调用方法。我可以,但为什么我应该在回到我之前调用一个碰巧执行某些异步操作的同步方法。

我已经看过使用WhenAll()然后使用Result的示例,但这对我不起作用。我已经尝试了所有不同的排列,但它要么锁定我的应用程序,要么告诉我任务尚未执行。

以下是我目前的情况:

public IEnumerable<BrokeredMessage>[] GetCombinedResults()
{
            var job = () => ServiceBus.TrackerClient.ReceiveBatchAsync(BatchLimit);
            Task<IEnumerable<BrokeredMessage>> task1 = _retryPolicy.ExecuteAsync<IEnumerable<BrokeredMessage>>(job);
            Task<IEnumerable<BrokeredMessage>> task2 = _retryPolicy.ExecuteAsync<IEnumerable<BrokeredMessage>>(job);
            IEnumerable<BrokeredMessage>[] results = Task.WhenAll<IEnumerable<BrokeredMessage>>(task1, task2).Result;
            return results;
}

但调用结果会导致锁定。我已经读过这样做会发生死锁但是已经将其作为其他问题的答案。 如果我调用Task.WaitAll()并且不关心结果,这种类型的设置工作正常。当我想要从任务返回的结果时,不确定为什么这变得困难。我尝试过使用Task.Run但是在得到结果之前它会退出我的方法。

1 个答案:

答案 0 :(得分:5)

您似乎对使用异步进行扇出并行感兴趣。这是完全有效的事情。没有必要使整个调用链异步以利用扇出并行性。

你偶然发现了通常的ASP.NET死锁。您可以使用Task.Run作为一种简单,自动防故障的方法来避免它。首先,让GetCombinedResults异步使其保持简单和一致:

public async Task<IEnumerable<BrokeredMessage>[]> GetCombinedResultsAsync()
{
            var job = () => ServiceBus.TrackerClient.ReceiveBatchAsync(BatchLimit);
            Task<IEnumerable<BrokeredMessage>> task1 = _retryPolicy.ExecuteAsync<IEnumerable<BrokeredMessage>>(job);
            Task<IEnumerable<BrokeredMessage>> task2 = _retryPolicy.ExecuteAsync<IEnumerable<BrokeredMessage>>(job);
            IEnumerable<BrokeredMessage>[] results = await Task.WhenAll<IEnumerable<BrokeredMessage>>(task1, task2);
            return results;
}

这种方法显然是正确的。它不会混合同步和异步。这样称呼:

var results = Task.Run(() => GetCombinedResultsAsync()).Result;

这样做的原因是GetCombinedResultsAsync现在没有同步上下文就会执行。