.net中使用httpclient发送多个请求,不会被超时链接阻塞

问题描述 投票:0回答:2

我的使用场景: 我有很多Url链接,我会定期请求它们来判断服务是否正常。并且这些URL的状态会显示在客户端

问题: 如果其中一个Url超时,其他Url将一起等待。我该如何处理这种情况?比如Url1超时后不阻塞其他请求(其他url会先返回结果)。

如何通过API返回并行运行的结果(或者持续返回结果)?让客户端显示更加友好。比如先返回正常的URL结果,等待超时后再返回超时结果。

下面的Test1和Test2是我的两次尝试,但都没有达到预期的效果。

string[] urls = new string[]
{
    "https://localhost:7268/api/Timeout",
    "https://www.google.com:81",
    "https://url1",
    "https://url2"
};

// Get Data
async Task<HttpResponseMessage> HttpRequest2Async(string url, CancellationToken cancellationToken = default)
{
    HttpClient httpClient = new HttpClient();
    
    var responseMessage = await httpClient.GetAsync(url, cancellationToken);
    
    return responseMessage;
}

// Test1 When Url1 times out, other Urls behind will wait.
List<HttpResponseMessage> urlResponses = new();

foreach (string url in urls)
{
    var responseMessage = await HttpRequest2Async(url, default);
    
    urlResponses.Add(responseMessage);
}

// Test2 As long as there is a Url timeout, all Urls will wait.
var tasks = new List<Task<HttpResponseMessage>>();

foreach (string url in urls)
{
    var task = HttpRequest2Async(url, default);
    
    tasks.Add(task);
}

var res = await Task.WhenAll(tasks);

结果:

https://localhost:7268/api/Timeout 后面的 Url 会等待其完成后再继续执行。 enter image description here

所有 URL 将等待 https://localhost:7268/api/Timeout 完成后再返回结果。 enter image description here

c# .net asp.net-web-api async-await parallel-processing
2个回答
1
投票

如果其中一个Url超时,其他Url将一起等待。

^ 这是不精确的。更准确的说法是:由于代码的组织方式是在处理任何 http 响应之前收集所有 http 响应,因此缓慢的请求会阻止处理(如果任何请求导致超时,则这是最明显的) ,因为在请求超时之前需要花费很长时间)。

我可以看到 4 个选项:

  1. 重新组织代码,以便在处理所有响应之前不等待它们。 像这样的东西:
    ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = n }; 
    await Parallel.ForEachAsync(urls, parallelOptions, async (uri, cancellationToken) =>
    {
        var r = await client.GetAsync(uri, cancellationToken);
     
        ... process the response here, not after all GetAsyncs are finished
    });
    
    这里的重点是
    for all {fetch;process}
    (与
    for all {fetch}; for all {process}
    )。
  2. 使用
    Task.WhenAny()
    而不是
    WhenAll
    并在任务完成后开始处理任务。
  3. 使用更积极的全局超时:HttpClient.Timeout Property
  4. 对每个请求使用更积极的超时(使用 CancellationTokenSource 并将取消令牌传递给
    GetAsync

0
投票

以下是我后来找到的解决方案。我现在再次回复,希望能帮助到其他人。

.NET有一个实时通信框架SignalR,可以让前后端实时通信,实时显示结果。并且可以使用任务调度框架Quartz.NET来调度监控任务。

这个问题的关键在于不懂的人如何找到合适的解决方案。使用什么语言、框架、技术可能是很多人都会遇到的问题。后来我也是用GPT了解到的,所以遇到这个问题最好的办法可能就是向其他有经验的人请教。

© www.soinside.com 2019 - 2024. All rights reserved.