Я хочу иметь метод, который запускает некоторую обработку, которая длится не более секунды, спит 5 минут и повторяется. Я также хочу, чтобы пользователь мог выйти из сна и уйти изящно. Я хочу, чтобы это работало в течение дня, не потребляя слишком много системных ресурсов. Каков лучший шаблон дизайна для этого?

Вот моя первая попытка:

  • Я использую поток, чтобы ждать и делать обработку. Я не уверен, должен ли я использовать поток, поток пула потоков или задачу. Я не думаю, что это должно быть задачей, потому что нет никаких асинхронных операций ввода-вывода. Я также не думаю, что мне следует использовать таймер, потому что я хочу иметь возможность аккуратно остановить поток, не дожидаясь следующего интервала.
  • Я использую AutoResetEvents для сигнализации между двумя потоками. Это позволяет внутреннему коду запускаться либо когда время истекло, либо когда пользователь хочет выйти.
  • Я прошу прощения, если этот вопрос является дубликатом. Если так, я не могу найти это.

Вот мой код:

var areCanContinue = new AutoResetEvent(false);
bool shouldContinue = true;

var thread = new Thread(obj =>
{
    while (true)
    {
        areCanContinue.WaitOne(TimeSpan.FromMinutes(5));
        if (shouldContinue)
        {
            Process();
        }
        else
        {
            break;
        }
    }
});
thread.Start();

string response;
do
{
    Console.WriteLine("Press 'q' to quit");
    response = Console.ReadLine();
} while (response != "q");

shouldContinue = false;
areCanContinue.Set();
2
user2023861 24 Апр 2017 в 23:47

2 ответа

Лучший ответ

Задачи не обязательно для операций ввода-вывода. Фактически, это хороший вариант использования Task.Delay (который внутренне оборачивает таймер):

public static async Task ProcessAsync(CancellationToken cancellationToken)
{
    try
    {
        while (true)
        {
            await Task.Delay(TimeSpan.FromMinutes(5), cancellationToken).ConfigureAwait(false);

            Process();
        }
    }
    catch (TaskCanceledException)
    {
        // Cancellation requested, do whatever cleanup you need then exit gracefully
    }
}

Тогда использовать это:

var cancellationTokenSource = new CancellationTokenSource();

var task = ProcessAsync(cancellationTokenSource.Token);

string response;
do
{
    Console.WriteLine("Press 'q' to quit");
    response = Console.ReadLine();
} while (response != "q");

cancellationTokenSource.Cancel();

task.Wait(); // Wait for the task to finish

В зависимости от ваших требований вы также можете напрямую использовать таймер:

var timer = new Timer(_ => Process(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));

string response;
do
{
    Console.WriteLine("Press 'q' to quit");
    response = Console.ReadLine();
} while (response != "q");

timer.Dispose(); // Stop the timer
4
Kevin Gosse 24 Апр 2017 в 21:03

Надеюсь это поможет.

class Program
{
    static void Main(string[] args)
    {
        Operation op = new Operation();
        var tokenSource = new CancellationTokenSource();
        Task.Factory.StartNew( async () => await op.LongRunningApplication(tokenSource.Token));
        while(true)
        {
            Console.WriteLine("PRINT STOP for Cancellation...");
            var str = Console.ReadLine();
            if(string.Compare(str, "Stop", true) == 0)
            {
                Console.WriteLine("Cancellation Requested...");
                tokenSource.Cancel();
                Task.Delay(TimeSpan.FromSeconds(30)).Wait(); // Making Sure that It stops gracefully since this is console app
                break;
            }
        }
        Console.WriteLine("Completed");
    }
}

public class Operation
{
    public async Task LongRunningApplication(CancellationToken token)
    {
        Console.WriteLine("Starting long Running application....");
        while (true)
        {
            await Task.Delay(1000);   // Your Operation
            Console.WriteLine("Wating...");
            for (int i = 0; i < 30; i++)
            {
                await Task.Delay(TimeSpan.FromSeconds(10));  // Wait For 5 Mins (10 sec , 30 intervals)
                if (token != null && token.IsCancellationRequested)
                {
                    Console.WriteLine("Stopping GraceFully..");
                    return;
                }
            }
        }
    }
}
0
loneshark99 24 Апр 2017 в 22:07
43597450