组合来自异步方法的结果并同步返回(Combine Results from Async Method and Return Synchronously)

编程入门 行业动态 更新时间:2024-10-27 04:25:35
组合来自异步方法的结果并同步返回(Combine Results from Async Method and Return Synchronously)

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

似乎有一个假设,如果你正在调用异步方法,你想在工作完成时返回调用者(即:一些长时间运行的任务)。 但是,我根本不需要这个。 我想等待任务完成,然后拿出我的组合列表并返回。

首先,我不想用async标记我的调用方法。 我可以,但为什么我应该,我无意中调用了一个同步方法,在返回给我之前恰好执行一些异步操作。

我已经看过使用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,​​但是在获得结果之前它会退出我的方法。

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.

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 (i.e.: 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. 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. 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.

最满意答案

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

你偶然发现了通常的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在没有同步上下文的情况下执行。

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. You can use Task.Run as a simple, fail-safe way to avoid it. First, let's make GetCombinedResults async to keep it simple and consistent:

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.

更多推荐

本文发布于:2023-07-19 02:41:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1171506.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:组合   方法   Combine   Results   Synchronously

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!