我无法用清楚的语言向自己解释为什么由Timer生成的Task工作得很好但是由Task生成的Timer不会.
所有相关代码都包含在下面,因此您可以轻松地重现它.
Form.cs:
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());
}
}
Run Code Online (Sandbox Code Playgroud)
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));
}
}
Run Code Online (Sandbox Code Playgroud)
ProcessDelay.cs:
public class ProcessDelay
{
private string name;
private int delay;
private Timer timer;
public ProcessDelay(string name, int delay)
{
this.name = name;
this.delay = delay;
}
public void Start()
{
timer = new Timer();
timer.Interval = delay;
timer.Tick += timer_Tick;
timer.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
//these work either way, as long as the task
// is NOT spawn in the main loop.
//TimerProc();
TimerProcTask();
}
private void TimerProcTask()
{
Task.Factory.StartNew(() => TimerProc());
}
private void TimerProc()
{
timer.Stop();
MessageBox.Show(name, delay.ToString());
}
}
Run Code Online (Sandbox Code Playgroud)
啊,计时器..NET中有四个,每个行为略有不同.您正在使用System.Windows.Forms.Timer.
此计时器使用Win32消息队列来触发计时器事件(WM_TIMER).创建计时器的线程timer_Tick是执行回调方法()的线程.线程需要一个消息泵才能执行定时器.
告诉任务在当前的SynchronizationContext上运行会使它工作:
Task.Factory.StartNew(() => p.Start(),
CancellationToken.None,
TaskCreationOptions.LongRunning,
TaskScheduler.FromCurrentSynchronizationContext());
Run Code Online (Sandbox Code Playgroud)
这实际上会调用发生在UI线程上的调用,所以对我来说这似乎毫无意义,如果你所做的就是调用p.Start()方法(几乎是单线程的).
请注意System.Windows.Forms.Timer该类的备注部分:
此Windows计时器专为使用UI线程执行处理的单线程环境而设计.它要求用户代码具有可用的UI消息泵,并且始终在同一线程中操作,或者将调用编组到另一个线程上.
如果希望定时器调用实际在单独的线程上执行,则可以使用System.Threading.Timer(或System.Timers.Timer此类的包装器).如果需要计时器回调来更新UI,则需要封送对UI线程的UI更新调用.但是,您可以确保在单独的线程上完成任何处理密集型工作,并且只在UI线程上完成最少量的代码(例如,实际更新控件)以保持响应.
| 归档时间: |
|
| 查看次数: |
175 次 |
| 最近记录: |