简体   繁体   English

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

[英]Combine Results from Async Method and Return Synchronously

I've read many posts where people have faced similar issues but they seem to make assumptions that don't apply or their code simply does not work for me. 我读过很多帖子,人们都遇到过类似的问题,但是他们似乎做出了不适用的假设,或者他们的代码根本不适合我。 I need to combine results from asynchronous methods. 我需要结合异步方法的结果。 The ONLY thing async that I want is the combining of the results. 我想要的唯一异步的是结果的组合。 Since the Azure Service Bus will only allow me to grab 256 messages at a time, I want to send off multiple requests to get a few batches at once and make it into one list. 由于Azure Service Bus一次只允许我抓取256条消息,因此我想发出多个请求以一次获取几批并将其放入一个列表。

There seems to be an assumption that if you are calling an async method you want to return to the caller while the work completed (ie: some long running task). 似乎有一个假设,如果您正在调用异步方法,则想在工作完成时返回到调用方(即:一些长时间运行的任务)。 However, I don't want that at all. 但是,我一点都不想要。 I want to wait on the tasks to complete and then take my combined list and return it. 我想等待任务完成,然后将合并的列表返回。

Firstly I don't want to mark my calling method with async. 首先,我不想用异步标记我的调用方法。 I can but why should I, I am by all means calling an synchronous method that happens to be performing some asynchronous actions before getting back to me. 我可以但是为什么我应该调用同步方法,而该方法恰好在返回我之前执行一些异步操作。

I have seen examples using WhenAll() and then working with the Result, but this doesn't work for me. 我已经看到了使用WhenAll()然后使用Result的示例,但这对我不起作用。 I've tried all different permutations but it either locks up my app or it tells me the task hasn't been executed yet. 我尝试了所有不同的排列,但是它要么锁定了我的应用程序,要么告诉我任务尚未执行。

Here is what I have currently: 这是我目前拥有的:

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;
}

But calling results causes it to lock up. 但是调用结果会导致其锁定。 I've read deadlocks can occur doing this but have seen this proposed as an answer in other questions. 我读过这样做可能会发生死锁,但已将此建议作为其他问题的答案。 If I call Task.WaitAll() and care nothing on the results this type of setup works fine. 如果我调用Task.WaitAll()而不关心结果,则这种类型的安装程序可以正常工作。 Not sure why this becomes difficult when I want the returned results from the tasks. 不知道为什么当我想要任务返回的结果时,这变得很难。 I've tried using Task.Run but then it exits my method before ever getting the results. 我尝试使用Task.Run,​​但是在获得结果之前它会退出我的方法。

You seem to be interested in using async for fan-out parallelism. 您似乎对使用异步进行扇出并行处理感兴趣。 That's a totally valid thing to do. 那是完全合法的事情。 It is not necessary to make the entire call chain async to make use of fan-out parallelism. 不必使整个呼叫链都异步以利用扇出并行性。

You stumbled over the usual ASP.NET deadlock. 您偶然发现了通常的ASP.NET死锁。 You can use Task.Run as a simple, fail-safe way to avoid it. 您可以使用Task.Run作为避免故障的一种简单的故障安全方法。 First, let's make GetCombinedResults async to keep it simple and consistent: 首先,让我们使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;
}

This method is clearly correct. 这种方法显然是正确的。 It does not mix sync and async. 它不混合同步和异步。 Call it like that: 这样称呼它:

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

The reason this works is that GetCombinedResultsAsync executes without synchronization context now. 这样做的原因是GetCombinedResultsAsync现在无需同步上下文GetCombinedResultsAsync执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM