Как запустить задачу, используя только последний триггер в течение х секунд?

У меня есть функция, которая запускает задачу для запуска.

void function ()
{
  new Task(async () =>
  {
    // await network operation
  }).Start();
}

Функция может вызываться много раз очень часто. Но я не хочу, чтобы Задача запускалась каждый раз, я хочу, чтобы она запускалась только на последнем триггере в течение, скажем, 5 секунд.

Вот шаги к тому, что я хочу сделать именно

  1. функция () вызывается
  2. Задержка на 5 секунд
  3. если функция () была вызвана в течение этих 5 секунд, я хочу отменить все отложенные задачи и снова начать задержку в 5 секунд
  4. Если функция () не была вызвана в течение этих 5 секунд, я хочу запустить задачу

Пожалуйста, наставьте меня, как я это сделаю в C# .NET 4.5

1 ответ

Решение

В следующем коде показано простое консольное приложение, которое запускает задачу через 5 секунд и отменяет текущую задачу, если запускается новая:

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Starting");
        Console.WriteLine("Press any key to call method or press Esc to cancel");

        do
        {
            Method();
        } while (Console.ReadKey(true).Key != ConsoleKey.Escape);
    }

    static Task delayTask = null;
    static CancellationTokenSource cancellationTokenSource = null;

    static void Method()
    {
        Console.WriteLine("Method called");

        if (delayTask != null)
        {
            cancellationTokenSource.Cancel();
        }

        cancellationTokenSource = new CancellationTokenSource();
        delayTask = Task.Delay(5000, cancellationTokenSource.Token);
        delayTask.ContinueWith((t) => {
            Console.WriteLine("Task running...");
        }, TaskContinuationOptions.NotOnCanceled);
    }
}

Код не использует async/await, потому что их нельзя легко использовать в консольном приложении (консольное приложение не имеет SynchronizationContext). При использовании этого кода в приложении WinForms, WPF или ASP.NET вы можете легко использовать async/await для улучшения кода. Тем не менее, он показывает основную идею использования CancellationTokenSource и объединение задержки с другой задачей.

Обычным термином для этого будет "debounce", и он обсуждается здесь: C# event debounce

Другие вопросы по тегам