【问题标题】:Task cancelled exception even though the method call(from one API to another API) is awaited即使等待方法调用(从一个 API 到另一个 API),任务取消异常
【发布时间】:2020-07-21 06:44:54
【问题描述】:

我的要求是异步处理每个请求的图像,一旦处理完所有请求的图像,它们就会被压缩。所以为此我需要等到所有图像都处理完毕。

对列表中的每个项目使用for 循环来异步调用第二个API 的方法。但是,我需要等待对第二个 API 方法的所有调用执行,然后再转到代码中的下一行。

第一个 API:

public async void SegregateRecordsByRequestAndMerge(List<ClassB> listCDF, List<ClassA> records, string filePath)
{    
List<ClassA> RequestList = records.GroupBy(x => x.RequestId)
  .Select(g => g.First())
  .ToList();
Task[] taskList = new Task[RequestList.Count];
for (int i = 0; i < RequestList.Count; i++) // reqList in RequestList)
{
  ClassA reqList = new ClassA();
  reqList = RequestList[i];
  List < ClassA> recordsByRequest = records.Where(x => x.RequestId == reqList.RequestId).ToList();
  ModelA serviceInput = new ModelA();
  serviceInput.ClassBProperty = listCDF;
  serviceInput.ClassAProperty = recordsByRequest;
  taskList[i] = (Task.Factory.StartNew(() => ProcessImages(serviceInput, "myroute/processimage")));
}
Task.WaitAll(taskList, 600000);
}

这就是服务调用的方式

public void ProcessImages(CodingRecordAndCDFModel myServiceInput, string resource)
{
  var client = new ServiceClient(BaseUrl)
                   {
                    Resource = resource
                   };
  client.Post(JsonConvert.SerializeObject(myServiceInput).ToString());
}

第二个 API(图像处理器):

[HttpPost, Route("myroute/processimage"), ResponseType(typeof(string))]
public void GeneratePDFs([FromBody] string pdfServiceInput) {
  if (!ModelState.IsValid) {
    throw new Exception();
  }
  ModelA myServiceModel = new ModelA();
  myServiceModel  = JsonConvert.DeserializeObject <ModelA> (pdfServiceInput);
  //// Logic to Process images
}

我面临的问题是,即使我使用的是 WaitAll(),也会引发任务取消异常。 在第 2 个 API 中的方法完全执行之前,控件返回到第 1 个 API。

我尝试了多种方法,例如使用Parallel.ForEach()Task.Whenall()Task.DelayTaskCreationOptions.LongRunning,但它们都不起作用……它们都抛出了任务被取消的异常。

我需要控件等到所有对第二个 API 的调用都返回到第一个 API,然后执行一些其他逻辑。

有人可以建议应该做什么吗?或者有什么更好的方法来处理这个要求?

编辑 1:

我认为问题在于我正在尝试异步调用一个方法,这将创建 2 个不同的异步方法调用...并且由于我在每个异步方法上使用 await 或 waitall,所以第一次调用的执行是完成后,即使第二个 API 中有另一个线程在运行,控件也会返回到第一个 API。

如果有办法等待 for 循环或等待所有单独的异步调用返回,那么这将是解决方案。

【问题讨论】:

  • 只是提醒一下,idk 它完全相关,async/await 在 asp.net 核心与说具有主线程的 ui 应用程序中的行为不同:blog.stephencleary.com/2017/03/…
  • 也许问题出在第二个 API 上。你在那里使用异步方法吗?任何异步\等待?如果是这样,您需要将 async 关键字添加到 API 并设置返回类型 Task 而不是 void(即使您没有返回任何内容)
  • 是的,我也尝试过,使第二个 API 方法异步并返回任务。但它也不起作用。我想我理解了这个问题,但不知道如何解决它。请阅读编辑 1 了解可能发生的情况。
  • 您正在使用的这个 ServiceClient 类的命名空间是什么?也许您可以提供一个文档链接?
  • 我的意思是 - 我发现表示 REST 请求的方法是同步的,这很奇怪。如果这个ServiceClient 类有PostAsync 方法,我不会感到惊讶。在这种情况下,它会返回一个Task 或更可能是Task&lt;TResponse&gt;,然后您可以根据需要进行处理,例如,将其添加到您的taskList。当然,在这种情况下,您还可以将 ProcessImages 方法的签名更改为 Task ProcessImage(...) 并实际返回任务:return client.PostAsync(...);

标签: .net .net-core asp.net-core-webapi .net-core-3.1


【解决方案1】:

根据 David Fowl(Microsoft 架构师)use of async void in ASP.NET Core applications is ALWAYS bad. 的说法,还要小心,根据您必须处理的图像数量,如果线程池正在加载和加载,您可能会淹没线程池..

这个模式怎么样,只要你有权更新服务层。 注意:为简洁起见,我排除了您的一些业务逻辑..

public async Task SegregateRecordsByRequestAndMerge()
{
    List<ClassA> requestList = records.GroupBy(x => x.RequestId).Select(g => g.First()).ToList();
    var processTasks = new List<Task>();
    for (var i = 0; i < requestList.Count; i++)
    {
        processTasks.Add(ProcessImages(serviceInput, "myroute/processimage"));
    }

    await Task.WhenAll(processTasks);
}

public Task ProcessImages(CodingRecordAndCDFModel myServiceInput, string resource)
{
  var client = new ServiceClient(BaseUrl) { Resource = resource };
  await client.PostAsync(JsonConvert.SerializeObject(myServiceInput).ToString());
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    • 2017-06-11
    • 1970-01-01
    相关资源
    最近更新 更多