【发布时间】:2016-06-09 22:27:03
【问题描述】:
我的应用程序中有一个事件,它改变了对象的状态并引用该状态以在 10 秒后重置。但如果在这 10 秒内再次触发该事件,则该事件不会更改状态,而只是将计时器重置为零。
为了简明易懂,这是我的代码的作用
- 我有一个安排任务在 10 秒后运行的事件
- 如果某个类型的一个任务被调度,并且另一个相同的请求进来,则现有的未来任务的“执行时间”会被调整。
目前我正在使用在线程中操作的“ConcurrentQueue”进行此操作
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.Delay”。我仍在考虑如何处理它。任何想法将不胜感激。
这是我想做的事情 我希望根据 Task.Run 和/或 Task.Delay().ContinueWith 序列重写工作线程。
【问题讨论】:
-
发布您想要做的事情,而不是您尝试的方式。反应式扩展已经有计时器、窗口等。TPL 数据流已经有一个由委托处理的消息队列,可能包含延迟。或者你可以写
for(;;){...; await someMethod(someData); await Task.Delay(10000);} -
@PanagiotisKanavos 我想使用 TPL 重写代码。如果我的问题不够明显,请道歉。我会编辑。
-
但是什么你想要实现?每 10 秒只处理一条消息?消息之间延迟 10 秒?一次处理在 10 秒窗口内收到的所有消息?在 10 秒的窗口内只处理 一个 消息?
-
例如,Rx 的Throttle 可以丢弃传入的事件,并且在 10 秒的窗口中只处理其中一个。实际语法比文档简单得多
-
@PanagiotisKanavos 我再次道歉。我显然是一个糟糕的问题作者。我编辑了我的问题并添加了我的代码的作用。感谢您的耐心等待。
标签: c# multithreading