[英]Why does this ParallelForEachAsync-Method never return?
我尝试使用该项目中的 ParallelForEachAsync 方法异步和并行执行此代码: https : //github.com/Dasync/AsyncEnumerable 。 不幸的是,该方法永远不会返回。 SampleProduct 是一个简单的 DTO,它具有一个布尔属性和两个字符串属性。 GetOsmData 方法尝试通过 http 请求获取数据但经常抛出异常。
我的第一次尝试没有使用 .ConfigureAwait(false),但结果相同......如果我用产品列表 (products.Count = 8) result.Count 尝试这种方法,结果总是以 7 停止。
private async Task<ConcurrentBag<SampleProduct>> CheckOsmDataAsync(List<SampleProduct> products)
{
var result = new ConcurrentBag<SampleProduct>();
await products.ParallelForEachAsync(
async product =>
{
OsmData osmData;
try
{
osmData = await GetOsmData(_osmUrl.Replace("articlenumber", product.MaterialNumber.ToString())).ConfigureAwait(false);
}
catch (Exception e)
{
osmData = null;
}
if (osmData != null && osmData.PrintingData.Count > 0)
{
product.OsmPrintImageAvailable = true;
}
else
{
product.OsmPrintImageAvailable = false;
}
result.Add(product);
},
// 0 => Chooses a default value based on the processor count
maxDegreeOfParallelism: 0
);
return result;
}
在某些情况下, GetOsmData
方法是否可能永远不会返回? 为了排除这种可能性,您可以在合理的持续时间后强制其超时。 您可以使用下面的扩展方法来实现它:
public static Task<T> TimeoutAfter<T>(this Task<T> task, int timeout)
{
var delayTask = Task.Delay(timeout).ContinueWith<T>(_ => throw new TimeoutException(),
TaskContinuationOptions.ExecuteSynchronously);
return Task.WhenAny(task, delayTask).Unwrap();
}
可以这样使用:
osmData = await GetOsmData(_osmUrl.Replace("articlenumber",
product.MaterialNumber.ToString())).TimeoutAfter(5000).ConfigureAwait(false);
这不是永久性的修复,因为我们不知道GetOsmData
任务下一步将做什么,因为它现在已经变成流氓 。 糟糕的情况是,它将使线程池线程永远被占用,并且由于过多的流氓任务,线程池迟早会耗尽。 希望这不是您要处理的问题,因为如果是这样,这并不是一个容易解决的问题。
在同事的帮助下,我可以解决问题...问题不在于方法本身内部,而仅在于调用方法的方式。 我称它为主/ UI线程同步。 这似乎造成了僵局。 使调用方法异步并等待CheckOsmDataAsync()解决了该问题。
不过,感谢您的回复!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.