Таймеры анонимных параллельных задач? - PullRequest
2 голосов
/ 16 декабря 2010

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

Оптимально я хотел бы что-то вроде:

            Task.Factory.StartNew(() =>
            {
                 Timer.Do(TimeSpan.FromMilliSeconds(200),() => ShouldCancel(), ()=>
                 {
                     //DoStuff
                 });
            });

с использованием цикла while / thread-sleep не кажется оптимальным.Я думаю, я мог бы определить и использовать обычный таймер, но он кажется немного неуклюжим ...

Ответы [ 3 ]

3 голосов
/ 22 марта 2011

Как насчет чего-то вроде следующего. Я уверен, что API можно немного почистить.

Очки на заметку:

Метод DoWork должен поддерживать совместную отмену, это единственный подход отмены, поддерживаемый библиотекой параллельных задач.

Таймер должен запускаться внутри Задачи, иначе Задача может быть создана и запланирована, но не выполнена, и таймер будет временем ожидания задачи, а не временем выполнения.

Если вы хотите предоставить другие внешние механизмы для отмены (другие токены), тогда вам нужно перейти в другой контекст и связать их. См .: CancellationTokenSource.CreateLinkedTokenSource

Это только приблизительно, как System.Threading.Timer только с точностью до миллисекунды. Это должно быть достаточно, чтобы ограничить выполнение задачи на несколько секунд.

public static class TimeLimitedTaskFactory
{
    public static Task StartNew<T>
        (Action<CancellationToken> action, int maxTime)
    {
        Task tsk = Task.Factory.StartNew(() =>
        {
            var cts = new CancellationTokenSource();
            System.Threading.Timer timer = new System.Threading.Timer(o =>
            {
                cts.Cancel();
                Console.WriteLine("Cancelled!");
            }, null, maxTime, int.MaxValue);
            action(cts.Token); 
        });
        return tsk;
    }
}

class Program
{
    static void Main(string[] args)
    {
        int maxTime = 2000;
        int maxWork = 10;

        Task tsk = TimeLimitedTaskFactory
                   .StartNew<int>((ctx) => DoWork(ctx, maxWork), maxTime);

        Console.WriteLine("Waiting on Task...");
        tsk.Wait();
        Console.WriteLine("Finished...");
        Console.ReadKey();
    }

    static void DoWork(CancellationToken ctx, int workSize)
    {
        int i = 0;
        while (!ctx.IsCancellationRequested && i < workSize)
        {
            Thread.Sleep(500);
            Console.WriteLine("  Working on ", ++i);
        }
    }
}
1 голос
/ 12 июня 2012

Вы также можете использовать RX library .

var timerTask = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(3));
timerTask.Subscribe(x =>
                                    {
                                        //Do stuff here
                                    });
0 голосов
/ 10 февраля 2011

Я думаю, это то, что вы хотите:

var cancelToken = new CancellationTokenSource();
var tt = Task.Factory.StartNew(obj =>
                                     {
                                         var tk = (CancellationTokenSource) obj;
                                         while (!tk.IsCancellationRequested)
                                         {
                                             if (condition)//your condition
                                             {
                                                 //Do work
                                             }
                                             Thread.Sleep(1000);
                                          }
                                      }, cancelToken);
...