Почему медленная отмена Task.Delay? - PullRequest
0 голосов
/ 22 января 2019

Я создал тестовую программу, которая запускает 1000 задач, которые выполняют Task.Delay со случайной задержкой от 20 до 30 секунд. Похоже, что отмена этой операции занимает около 10 секунд ..

Вот моя тестовая программа:

class Program
{
    static async Task MainAsync()
    {
        CancellationTokenSource tokenSource = new CancellationTokenSource();

        List<Task> allTask = new List<Task>();
        Random r = new Random(9);

        async Task SafeDelay(int delay, CancellationToken token)
        {
            try
            {
                await Task.Delay(delay, token);
            }
            catch (TaskCanceledException)
            {
            }
        }

        for (int i = 0; i < 1000; i++)
        {
            var randomDelay = r.Next(20000, 30000);
            allTask.Add(SafeDelay(randomDelay, tokenSource.Token));
            ;
        }

        Stopwatch stopwatch = new Stopwatch();

        var cancelTask = Task.Delay(1000).ContinueWith(t =>
        {
            Console.Out.WriteLine("1000ms elapsed. Cancelation request start");;
            stopwatch.Start();
            tokenSource.Cancel();
        });

        await Task.WhenAll(allTask);
        await cancelTask;

        stopwatch.Stop();

        Console.WriteLine($"Cancelation done after {stopwatch.ElapsedMilliseconds} ms");
    }

    static void Main(string[] args)
    {
        Console.WriteLine("Started");
        Task.Run(MainAsync).GetAwaiter().GetResult();
        Console.WriteLine("End");
        Console.ReadLine();
    }
}

Мой результат с .NET Core 2.1:

Cancelation done after 9808ms

Почему отмена Task.Delay такая медленная и есть ли способ ее улучшить?

Мой результат с .NET 4.7.1:

Cancelation done after 6200ms

Ответы [ 2 ]

0 голосов
/ 22 января 2019

Когда я запускаю это с F5 , я получаю аналогичный результат.
Запустите его с помощью Ctrl + F5 (без отладчика), и он отменит менее чем за 50 мс.

Итак, вы на самом деле рассчитываете 1000 исключений, щекочущих отладчик. Отладчик может мешать и другим точкам выполнения. Всегда запускайте тесты в режиме Release, без отладчика.

0 голосов
/ 22 января 2019

Нет репродукции с кодом вопроса.Используя его как есть, я получаю:

Started
1000ms elapsed. Cancelation request start
Cancelation done after 38 ms
End

Нет репро с очищенным кодом:

static async Task SafeDelay(int delay, CancellationToken token)
{
    try
    {
        await Task.Delay(delay, token);
    }
    catch (TaskCanceledException)
    {
    }
}


private static async Task Main()
{
    //Set 1000 ms timeout
    var tokenSource = new CancellationTokenSource(1000);
    var stopwatch = Stopwatch.StartNew();

    var allTask = new List<Task>();
    Random r = new Random(9); 


    for (var i = 0; i < 1000; i++)
    {
        var randomDelay = r.Next(20000, 30000);
        allTask.Add(SafeDelay(randomDelay, tokenSource.Token));
    }
    Console.WriteLine($"All {allTask.Count} tasks running after {stopwatch.ElapsedMilliseconds} ms");

    await Task.WhenAll(allTask);
    stopwatch.Stop();

    Console.WriteLine($"Cancelation done after {stopwatch.ElapsedMilliseconds} ms");
}

Это дает:

All 1000 tasks running after 8 ms
Cancelation done after 1044 ms

У CancellationTokenSource 1000 мстайм-аут.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...