简体   繁体   English

为什么这个 ParallelForEachAsync-Method 永远不会返回?

[英]Why does this ParallelForEachAsync-Method never return?

I try to execute this code async and parallel by using the ParallelForEachAsync method from this project: https://github.com/Dasync/AsyncEnumerable .我尝试使用该项目中的 ParallelForEachAsync 方法异步和并行执行此代码: https : //github.com/Dasync/AsyncEnumerable Unfortunately the method never returns.不幸的是,该方法永远不会返回。 The SampleProduct is a simple DTO which has a boolean property and two string properties. SampleProduct 是一个简单的 DTO,它具有一个布尔属性和两个字符串属性。 The GetOsmData-method tries to get data via http-request but often throws an exception. GetOsmData 方法尝试通过 http 请求获取数据但经常抛出异常。

My first attempt was without .ConfigureAwait(false), but has the same result... If I try this method with a list of products (products.Count = 8) result.Count always stopps by 7.我的第一次尝试没有使用 .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;
        }

Is it possible that the method GetOsmData never returns under some conditions? 在某些情况下, GetOsmData方法是否可能永远不会返回? To rule out this possibility you could force it to timeout after a reasonable duration. 为了排除这种可能性,您可以在合理的持续时间后强制其超时。 You can use the extension method bellow to achieve it: 您可以使用下面的扩展方法来实现它:

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();
}

It can be used like this: 可以这样使用:

osmData = await GetOsmData(_osmUrl.Replace("articlenumber",
    product.MaterialNumber.ToString())).TimeoutAfter(5000).ConfigureAwait(false);

This is not a permanent fix because we don't know what the GetOsmData task will do next, since now it has become rogue . 这不是永久性的修复,因为我们不知道GetOsmData任务下一步将做什么,因为它现在已经变成流氓 A bad scenario is that it will keep a thread-pool thread occupied forever, and sooner or later the thread-pool will be exhausted because of too many rogue tasks. 糟糕的情况是,它将使线程池线程永远被占用,并且由于过多的流氓任务,线程池迟早会耗尽。 Hopefully this is not the problem you are dealing with, because if it is, it's not an easy problem to solve. 希望这不是您要处理的问题,因为如果是这样,这并不是一个容易解决的问题。

With the help of my colleague I could solve the problem... The problem was not inside the method itself, but only how it was called. 在同事的帮助下,我可以解决问题...问题不在于方法本身内部,而仅在于调用方法的方式。 I called it form the Main/UI-Thread synchronously. 我称它为主/ UI线程同步。 That seems to have caused a deadlock. 这似乎造成了僵局。 Making the calling method async and awaiting the CheckOsmDataAsync() solved the problem. 使调用方法异步并等待CheckOsmDataAsync()解决了该问题。

Nevertheless thanks for your responds! 不过,感谢您的回复!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM