使用任务执行延迟"timer-style"操作



我的应用程序中有一个事件,它改变了对象的状态,并在10秒后将该状态重置。但是,如果在这10秒内再次触发该事件,该事件不会改变状态,只是将计时器重置为零。

为了使其简洁易懂,以下是我的代码所做的

  1. 我有一个事件,它安排任务在10秒后运行
  2. 如果某个特定类型的任务被调度,而另一个请求也来了,那么现有未来任务的"执行时间"就会调整

当前我使用线程中正在操作的"并发队列"来执行此操作

public class ToDo
{
public DateTime Expires { get; set; }
public Action StuffToDo { get; set; }
}

然后我的线程

public void MyWorkerThread(object parameters)
{
while (!<check if cancellation requested>)
{
ToDo stuff;
if (myConcurrentQueue.TryDequeue(out stuff))
{
if (DateTime.Now > stuff.Expires)
{
Task.StuffToDo.Invoke();
}
else 
{
// queue it back if it is not time to execute it
//
myConcurrentQueue.Enqueue(stuff);
}
}
}
}

这是我的事件处理程序,用于对任务进行排队

private ConcurrentDictionary<ToDo> _todoDictionary = new ConcurrentDictionary<ToDo>();
private ConcurrentQueue<ToDo> myConcurrentQueue = new ConcurrentQueue<ToDo>();
public void MyEventFired(MyEventArgs e)
{
ToDo todo = null;
if (_todoDictionary.ContainsKey(e.TaskType)) 
{
_todoDictionary.TryRemove(out todo);
if (DateTime.Now >= task.Expires) 
{
todo = new ToDo();
todo.StuffToDo = new Action(() => { /* stuff here */ });
}   
} 
else
{
todo = new ToDo();
todo.StuffToDo = new Action(() => { /* stuff here */ });
}
todo.Expires = DateTime.Now + TimeSpan.FromSeconds(10.0);
_todoDictionary.Add(e.TaskType, todo);
myConcurrentQueue.Enqueue(todo);
}

有人向我暗示,我可以使用TPL完成上述所有操作,我不需要工人线程,我只需要使用"任务。延迟"。我仍在考虑如何处理它。任何想法都将不胜感激。

以下是我想要做的我希望根据Task.Run和/或Task.Delay().ContinuteWith序列重写工作线程。

您当前的MyWorkerThread代码是一个繁忙的循环。它将CPU核心驱动到100%。你应该听到你的CPU风扇因为这个而旋转。

以下是我如何实现可重置延迟:

volatile int targetTicks = Environment.TickCount + (10 * 1000);
async Task WaitUntilTargetReachedAsync() {
while (true) {
var currentTicks = Environment.TickCount; //stabilize value
var targetTicksLocal = targetTicks; //volatile read, stabilize value
if (currentTicks >= targetTicksLocal) break; //Target reached.
await Task.Delay(TimeSpan.FromMilliseconds(targetTicksLocal - currentTicks));
}
}

CCD_ 2将恰好在达到CCD_ 3时完成。您可以随时向targetTicks添加时间,WaitUntilTimeoutAsync()将进行调整。通过这种方式,您可以将计时器重置为现在加10秒:

targetTicks = Environment.TickCount + (10 * 1000);

既然你有一项任务可以在你需要的时候完成,你就可以在此基础上采取行动:

targetTicks = Environment.TickCount + (10 * 1000); //Initial timer configuration.
await WaitUntilTimeoutAsync();
InvokeMyAction();

最新更新