我做了一个计时器,我可以设定时间,我想等待,然后做一些事情。 所以这是我的短计时器功能:
private void Sleep(int interval, Action action)
{
System.Windows.Forms.Timer mytimer = new System.Windows.Forms.Timer();
mytimer.Interval = interval; //interval is in ms
mytimer.Start();
mytimer.Tick += (s, e) =>
{
action();
mytimer.Stop();
};
}
我在循环中使用这个计时器:
foreach (string word in words)
{
Sleep(5000, ()=> myAction());
}
没有循环计时器很棒,但在循环中它不会工作,因为循环不会停止并等待那些5秒。它会立即完成所有操作,并且一次又一次地启动计时器。
所以我试图找出的是如何让我的循环等到时间用完并执行myAction()。我正在处理表单应用程序,所以所有threadin睡觉都不会在这里工作。此外,我尝试了所有其他计时器,但他们使用了太多的CPU。
答案 0 :(得分:1)
最好将所有操作添加到队列中,然后在计时器结束后执行
目前只有一次您的代码建议您在每次调用Sleep
方法时创建新的计时器
您正在使用的计时器也会在当前Window的主调度程序上运行,如果您想在另一个线程上指定并运行计时器,则可能需要使用DispatcherTimer
。
private Queue<Tuple<string,Action>> _queuedAction = new Queue<Tuple<string,Action>>();
然后
foreach(var word in words){
_queuedAction.Enqueue(new Tuple<string, Action>(word, ()=>{});
}
var timer= new System.Windows.Forms.Timer();
timer.Interval = interval;
timer.Elapsed += OnTimerElapsed;
timer.Start();
然后
private void OnTimerElapsed(object sender, EventArgs e){
if(!_queuedAction.Any()) return;
var tuple = _queuedAction.Dequeue();
//Execute your Action here.
var word = tuple.Item1;
var action = tuple.Item2;
action();
}
这里我们正在向队列中添加操作,每次间隔过去时,OnTimeElapsed
方法都会被调用,然后在其中执行操作。
否则,如果您正在寻找同步解决方案,我们可以简单地使用这样的
foreach(var word in words){
DoSomethingWithWord(word);
Thread.Sleep(5000);
}
答案 1 :(得分:0)
您的循环不会停止,因为计时器实际上并未执行任何暂停当前线程执行的命令。
虽然你的例子有点模糊,但我假设你正在寻找的是Task.Delay
内部使用计时器。您可以异步等待它,以便循环将控制权交还给调用者:
foreach (string word in words)
{
await Task.Delay(5000);
action();
}
请注意,这意味着您必须将方法标记为async Task
,或者将其标记为事件处理程序async void
。
答案 2 :(得分:0)
它&#34;似乎&#34;喜欢它立即再次发生是因为你的foreach
循环实际上没有任何延迟 - 以你的处理器循环的速度 - 并立即多次调用Sleep
,因此排队等待你的5000毫秒的所有计时器,然后在那之后全部解雇你的行动。
您可以执行此操作而不是foreach
循环并删除所有其他代码(即Sleep
方法):
System.Threading.Tasks.Task t = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
var timer = new System.Threading.Timer(new System.Threading.TimerCallback(x => this.Invoke(myAction)), null, 5000, 5000);
});
请注意以下几点:
计时器不阻止UI线程,因为它在一个单独的线程上运行,而你的代码会在循环时阻止用户界面。
正在使用的计时器类是System.Threading.Timer
,而不是System.Windows.Forms.Timer
(有关.NET计时器的详细解释,请参阅this)
如果您想在计时器内(即在myAction
代表内)对UI线程执行任何操作,则必须使用this.Invoke(myAction)
执行此操作,这是重要规则之一涉及UI线程的多线程操作。