【发布时间】:2020-04-12 15:36:59
【问题描述】:
我试图模拟一个场景,当我请求一次我的 api 服务时,我必须对不同的外部 API 或数据库等进行 4 次 IO 有界请求才能获得对我的示例的响应。
我想异步启动这些请求,如果我收到其中一个请求的否定响应(在我的示例中为 null),则在收到其中一个否定响应后立即停止所有请求。
根据我的示例,请求是同时启动的,即使我收到其中一个请求的否定响应,我也必须等到长请求(task4)完成。这意味着我至少能在 40 秒内得到结果。当我在第 20 秒收到来自第二个请求 (task2) 的空响应时,如何再不必要地停止工作 20 秒?
如果有可能我应该如何处理这种情况?
public class HomeController : Controller
{
public async Task<string> SampleAsyncAction()
{
var task1 = DoSomeIOAsync(10000);
var task2 = DoSomeIOAsync(20000);
var task3 = DoSomeIOAsync(30000);
var task4 = DoSomeIOAsync(40000);
var result = await Task.WhenAll(task1, task2, task3, task4);
if (result.Any(x=> x == null))
return "Error occurred";
return "Operation was done successfully in " + result.Sum().ToString() + "millisecond";
}
private int? DoSomeIO(int millisecond)
{
Thread.Sleep(millisecond);
if (millisecond == 20000)
return null;
return (millisecond);
}
private async Task<int?> DoSomeIOAsync(int millisecond)
{
return await Task.Run(() => DoSomeIO(millisecond));
}
}
【问题讨论】:
-
如果需要模拟异步调用,使用Task.Delay。不要使用 Thread.Sleep。然后你就可以消除 Task.Run 这通常是代码异味。
-
如果您想在其中一个镜头返回某个响应时继续,那么您为什么要使用 Task.WhenAll?你读过它的定义吗?这与您想要的相反。
-
看看这个:How can I await an array of tasks and stop waiting on first exception? 如果你可以让你的异步方法抛出异常而不是返回 null,你可以使用这个问题的解决方案。
-
非常感谢@mason。我知道 Task.Delay 更好,但我想模拟使用未声明为异步的函数。如果我使用像 ORM 这样没有异步选择能力的东西怎么办?那么我不应该使用 Task.Run() 将我从 db 中选择的同步方法更改为异步方法吗?
-
@mason 我在异步编程方面并不完美。我认为 whenall() 是我可以并行执行一些 IO 请求的唯一方法。你对这种情况有什么建议?
标签: c# asp.net-core asynchronous async-await