我正在尝试编写自己的调度程序;根据延迟,其背后的理由是所有提交的行动将按顺序执行。例如,如果时间为0
,我会安排延迟A
的行动5
,并在时间1
安排行动B
延迟2
,然后应B
首先执行3
,A
时应执行5
,然后public class MyScheduler
{
Task _task = new Task(() => { });
public MyScheduler()
{
_task.Start();
}
public void Schedule(Action action, long delay)
{
Task.Delay(TimeSpan.FromTicks(delay)).ContinueWith(_ =>
lock(_task) {
_task = _task.ContinueWith(task => action())
}
);
}
}
执行 var waiter = new Waiter(3);
int _count = 0;
mysched = new MyScheduler();
mysched.Schedule(() => { _count++; waiter.Signal(); });
mysched.Schedule(() => { Task.Delay(100).Wait(); _count *= 3; waiter.Signal(); });
mysched.Schedule(() => { _count++; waiter.Signal(); });
waiter.Await();
Assert.AreEqual(4, _count);
。
基本上,我想要做的是:
Waiter
此代码的相关测试将是:
Signal
在上面的代码中,Await
是一个在构造函数中初始化了内部变量的类; _count
方法递减内部变量和2
方法循环(并在每次迭代时休眠10毫秒),直到内部变量小于或等于零。
测试的目的是显示已按计划执行计划的操作。
大多数时候这是真的并且测试通过了,但在很少的情况下4
的结果值是{{1}}而不是{{1}}。我花了很多时间试图弄清楚为什么会发生这种情况,但我似乎无法弄明白,而且我对C#缺乏经验也没有帮助。
有人有任何建议吗?
答案 0 :(得分:4)
首先,_count
未与来自不同线程的访问同步。
我建议您根本不使用ContinueWith
;它是一个非常低级的方法,很容易弄错细节(例如,默认调度程序是TaskScheduler.Current
,这几乎不是你想要的)。您的常规逻辑代码应使用await
而不是ContinueWith
。
关于调度程序,现在几乎不可能成为开发自己的用例的好用例。有更好的可用的天才开发和经过充分测试。考虑Reactive Extensions:它们提供了几个调度程序,它们都是support scheduling。