Почему этот ParallelForEachAsync-метод никогда не возвращается? - PullRequest
1 голос
/ 29 апреля 2019

Я пытаюсь выполнить этот код асинхронно и параллельно, используя метод ParallelForEachAsync из этого проекта: https://github.com/Dasync/AsyncEnumerable. К сожалению, метод никогда не возвращается. SampleProduct - это простой DTO, который имеет логическое свойство и два строковых свойства. Метод GetOsmData пытается получить данные через http-запрос, но часто выдает исключение.

Моя первая попытка была без .ConfigureAwait (false), но с тем же результатом ... Если я попробую этот метод со списком продуктов (products.Count = 8), то получится. Количество всегда останавливается на 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;
        }

Ответы [ 2 ]

0 голосов
/ 30 апреля 2019

С помощью моего коллеги я смог решить проблему ... Проблема была не в самом методе, а только в том, как он вызывался.Я назвал это из Main / UI-Thread синхронно.Это, кажется, вызвало тупик.Выполнение асинхронного метода вызова и ожидание CheckOsmDataAsync () решило проблему.

Тем не менее, спасибо за ваши ответы!

0 голосов
/ 29 апреля 2019

Возможно ли, что метод 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 задание, так как теперь оно стало мошенником .Плохой сценарий состоит в том, что он будет постоянно удерживать поток пула потоков, и рано или поздно пул потоков будет исчерпан из-за слишком большого количества мошеннических задач.Надеюсь, это не та проблема, с которой вы сталкиваетесь, потому что, если это так, ее решить непросто.

...