【问题标题】:Best way to pause a loop with an internal async call in C#在 C# 中使用内部异步调用暂停循环的最佳方法
【发布时间】:2019-04-17 15:34:06
【问题描述】:

我正在向一个 API 发送大约 100,000 个 JSON 对象的列表,该 API 只能一个一个地接受它们,并且我正在异步发送它们。我知道 API 在内部将接收到的对象发送到一个队列,该队列似乎被所有这些请求阻塞,这导致我在其中一些请求之后收到“网关超时”错误。

我尝试将列表拆分成不同大小的批次,并在发送每个批次后使线程进入睡眠状态,但最终发生的情况是它在批次大小时出现相同的错误,我已经尝试过3000、2500 和 1000 批次,结果相同,线程似乎永远不会休眠。

这是有问题的代码:

public async Task TransferData(IEnumerable<MyData> data)  
{  
     var pages = Math.Ceil(data.Count() / 3000m);  

     for (var page = 0; page < pages; page++)  
     {  
         await TransferPage(data.Skip(page * 3000).Take(3000);
         Thread.Sleep(10000);  
     }  
}

private async Task TransferPage(IEnumerable<MyData> data)  
{  
     await Task.WhenAll(data.Select(p => webConnection.PostDataAsync(JsonConvert.SerializeObject(p, Formatting.None))));  
}

注意:webConnection 只是一个已经实例化了 HttpClient 的类,并对预期 URL 的数据执行 PostAsync。

对 TransferData 的调用是在控制台应用程序中完成的,如下所示:

try  
{  
   ...    
   dataManager.TransferData(data).Wait();
}
catch(AggregateException ex)
{
   ...
}
catch(Exception ex)
{
   ...
}

感谢您的指导。

更新:澄清一些在 cmets 中出现的混淆。外部 API 正在一一接收对象,如果您查看 WhenAll 内部的私有方法 TransferPage,IEnumerable 有一个 Select,其中调用了内部执行实际 HttpClient PostAsync 的方法.因此,对象被分批分组,并且在每批中它们被一个接一个地发送。我希望这能让它更清楚一点。

【问题讨论】:

  • 如果只能按顺序处理,为什么要并行发送?
  • 您需要等待Task.Delay。不要将 Thread.Sleep 与 async-await 混合使用。您也不要将 async-await 与 .Wait() 之类的阻塞调用混合使用,因为这会导致死锁
  • 正如@slaks 所说,帖子中的代码和文本不对齐 - 正如代码所示,“一个接一个”和 3000 个批次之间存在显着差异。
  • 所以你必须在线程睡眠之前使用 await Task.Delay() 也你缺少 ')"。但问题是你试图同时发送大量数据而不是一个一个地发送。跨度>
  • SemaphoreSlim 的情况。见link

标签: c# async-await dotnet-httpclient


【解决方案1】:

可能发生的情况是一个或多个PostDataAsync 任务抛出超时错误,导致任务失败。 Task.WhenAll 仅将它们捆绑到 AggregateException 中,并在列表中的所有任务完成后抛出它,这就是为什么您只会在批处理结束时看到异常的原因。

尽管您尝试节流,但您可能会压倒服务。您可能应该做几件事:

  • 改进异常处理和重试情况。您可以在 PostDataAsync 内部和/或外部执行此操作。即使您没有使服务不堪重负,您也将需要处理瞬时异常以处理网络故障等。
  • 用适当的限制实现替换您的批处理逻辑。 Serg 在 cmets 中链接的问题的答案是一个好的开始 - SemaphoreSlim 或 TPL Dataflow 是常见的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 2014-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多