也许我的大脑有点油炸所以我错过了一些很好的方法来做以下...我希望能够通过一个特定间隔运行的任务启动计时器并检查每个间隔的某些条件是否应该取消自己,最优雅的解决方案是什么?
最好我喜欢这样的东西:
Task.Factory.StartNew(() =>
{
Timer.Do(TimeSpan.FromMilliSeconds(200),() => ShouldCancel(), ()=>
{
//DoStuff
});
});
使用while / thread-sleep循环似乎不是最佳选择。我想我可以定义和使用一个普通的计时器,但它看起来有点笨拙...
答案 0 :(得分:3)
如下所示。我确定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 :(得分:1)
您也可以使用RX library。
var timerTask = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(3));
timerTask.Subscribe(x =>
{
//Do stuff here
});
答案 2 :(得分:-1)
我认为这就是你想要的:
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);