【问题标题】:Run parallel task and return the first completed task and run other in background to save results运行并行任务并返回第一个完成的任务并在后台运行其他任务以保存结果
【发布时间】:2020-08-10 16:22:24
【问题描述】:

我在 .NET CORE 3.1 中有一个 WebApi,我正在尝试从服务(其他第三方)获取结果。我在我的 API 中为同一个服务创建了多个请求,但每个请求的某些参数不同,每个请求从服务返回的结果都会不同,但结果的结构会相同。

由于所有请求都是相互独立的,我想并行运行所有请求。我想从我的 API 接收到服务后立即返回第一个结果,但我也想在后台运行所有其他请求并将结果保存在 REDIS 中。

我尝试创建一个示例代码来检查是否可能:

        [HttpPost]
        [Route("Test")]
        public async Task<SearchResponse> Test(SearchRequest req)
        {
            List<Task<SearchResponse>> TaskList = new List<Task<SearchResponse>>();
            for (int i = 0; i < 10; i++)
            {
                SearchRequest copyReq = Util.Copy(req); // my util function to copy the request
                copyReq.ChangedParameter = i; // This is an example, many param can changed
                TaskList.Add(Task.Run(() => DoSomething(copyReq)));
            }

            var finishedTask = await Task.WhenAny(TaskList);

          return  await finishedTask;
        }

        private async Task<SearchResponse> DoSomething(SearchRequest req)
        {
            // Here calling the third party service
             SearchResponse resp = await service.GetResultAsync(req);


           // Saving the result in REDIS
            RedisManager.Save("KEY",resp);

             return resp;            
        }

现在我想知道这是否是处理此问题的正确方法。如果有更好的方法,请指导我。

编辑

用例场景

我创建了一个网络应用程序,它将从我的 webapi 获取结果并显示结果。 WebApp 通过向我的 api 发送请求来搜索产品列表(可以是任何东西)。现在我的 api 创建了不同的请求,因为 source(假设是 Site1 和 Site2)的结果可能不同。

现在第三方处理对不同来源(Site1 和 Site2)的所有请求,并将结果转换为我的结果结构。我只需要提供我想从哪个站点获取结果的参数,然后在最后调用服务。

现在我想在任何来源(site1 或 site2)给我结果后立即将结果发送到我的 WebApp,并且在后台我想将其他来源的结果保存在 redis 中。这样我也可以在其他请求命中时从我的 webapp 中获取它。

【问题讨论】:

  • 您没有以有意义的方式描述您的用例,因此很难说。您想推迟工作,然后通过移出当前线程来推迟它。如果您想要回电,那么您要么需要请求状态,要么使用像 SignalR 这样的双向通信技术(超出范围)。因此,如果没有更具体的流程示例以及原因,就很难提出任何建议。您的“问题”不清楚,因此很难指导
  • 请给我们更多的背景信息,这样我们就能得到更清晰的画面,当然不会泄露敏感信息:)
  • 我已经更新了场景。请看一看!

标签: c# .net .net-core redis asp.net-core-3.1


【解决方案1】:

代码看起来不错;我只推荐一个调整:不要使用Task.RunTask.Run 导致线程切换,这里完全没有必要。

[HttpPost]
[Route("Test")]
public async Task<SearchResponse> Test(SearchRequest req)
{
  var TaskList = new List<Task<SearchResponse>>();
  for (int i = 0; i < 10; i++)
  {
    SearchRequest copyReq = Util.Copy(req); // my util function to copy the request
    copyReq.ChangedParameter = i; // This is an example, many param can changed
    TaskList.Add(DoSomething(copyReq));
  }

  return await await Task.WhenAny(TaskList);
}

private async Task<SearchResponse> DoSomething(SearchRequest req)
{
  // Here calling the third party service
  SearchResponse resp = await service.GetResultAsync(req);

  // Saving the result in REDIS
  RedisManager.Save("KEY",resp);

  return resp;            
}

请注意,这是使用即发即弃。在一般意义上,即发即弃是危险的,因为这意味着您不在乎代码是否失败甚至是否完成。在这种情况下,由于代码只是更新缓存,因此可以接受即发即弃。

【讨论】:

  • 如果假设没有例外,我剩下的任务是否有可能无法完成?
  • 是的。如果应用程序因任何原因退出,那么即发即弃的任务将在没有警告的情况下终止。
  • 感谢您的建议。我会遵循的。 :)
猜你喜欢
  • 2015-04-09
  • 1970-01-01
  • 2014-10-11
  • 1970-01-01
  • 2015-08-23
  • 2012-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多