C# 计时器按任务生成和任务按计时器生成
我不能很清楚地向自己解释为什么由计时器生成的任务工作得很好,而由任务生成的计时器工作得不好 所有相关代码都包含在下面,因此您可以轻松地复制它 表格C:C# 计时器按任务生成和任务按计时器生成,c#,timer,task,C#,Timer,Task,我不能很清楚地向自己解释为什么由计时器生成的任务工作得很好,而由任务生成的计时器工作得不好 所有相关代码都包含在下面,因此您可以轻松地复制它 表格C: private void Form1_Load(object sender, EventArgs e) { ProcessDelayList list = new ProcessDelayList(); foreach (ProcessDelay p in list) { //this works
private void Form1_Load(object sender, EventArgs e)
{
ProcessDelayList list = new ProcessDelayList();
foreach (ProcessDelay p in list)
{
//this works
p.Start();
//this does NOT work
//Task.Factory.StartNew(() => p.Start());
}
}
ProcessDelayList.cs:
public class ProcessDelayList : List<ProcessDelay>
{
public ProcessDelayList()
{
Add(new ProcessDelay("Process 1", 2000));
Add(new ProcessDelay("Process 2", 4000));
Add(new ProcessDelay("Process 3", 6000));
Add(new ProcessDelay("Process 4", 8000));
Add(new ProcessDelay("Process 5", 10000));
}
}
啊,计时器。NET中有四种,每种行为略有不同。您正在使用 此计时器使用Win32消息队列触发计时器事件(
WM\u timer
)。创建计时器的线程是执行回调方法(timer\u Tick
)的线程。线程需要一个消息泵才能执行计时器
告诉任务在当前SynchronizationContext上运行将使其工作:
Task.Factory.StartNew(() => p.Start(),
CancellationToken.None,
TaskCreationOptions.LongRunning,
TaskScheduler.FromCurrentSynchronizationContext());
不过,这实际上是在UI线程上封送调用,因此,如果您所做的只是调用p.Start()
注意System.Windows.Forms.Timer
类的备注部分:
此Windows计时器专为使用UI线程执行处理的单线程环境而设计。它要求用户代码有一个可用的UI消息泵,并且总是从同一个线程运行,或者将调用封送到另一个线程
如果希望计时器调用在单独的线程上实际执行,可以使用System.Threading.Timer
(或此类的System.Timers.Timer
包装器)。如果需要计时器回调来更新UI,则需要将该UI更新调用封送至UI线程。但是,您可以确保在单独的线程上完成任何处理密集型工作,并且在UI线程上只执行最少量的代码(例如,实际更新控件)以保持其响应性。是否可以尝试使用新任务(()=>p.Start()).Start()@thinklarge:InvalidOperationException:Start不能对已启动的任务调用。
Task.Factory.StartNew(() => p.Start(),
CancellationToken.None,
TaskCreationOptions.LongRunning,
TaskScheduler.FromCurrentSynchronizationContext());