首页 > 解决方案 > 运行并行任务并返回第一个完成的任务并在后台运行其他任务以保存结果

问题描述

我在 .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;            
        }

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

编辑

用例场景

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

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

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

标签: c#.net.net-coreredisasp.net-core-3.1

解决方案


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

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


推荐阅读