运行 并行任务和 return 第一个完成的任务和 运行 其他在后台保存结果

Run parallel task and return the first completed task and run other in background to save results

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

由于所有请求都是相互独立的,所以我想 运行 并行处理所有请求。我想 return 从我的 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;            
        }

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

编辑

用例场景

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

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

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

代码看起来不错;我只推荐一项调整:不要使用 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;            
}

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