[英]Control.Invoke vs Tasks with a TaskScheduler
我已经看遍了,我找不到答案。 使用它是更好、更坏还是无所谓:
{
...
RefreshPaintDelegate PaintDelegate = new RefreshPaintDelegate(RefreshPaint);
Control.Invoke(PaintDelegate);
}
protected void RefreshPaint()
{
this.Refresh();
}
...或者...
Task.Factory.StartNew(() =>
{
this.Refresh();
},
CancellationToken.None,
TaskCreationOptions.None,
uiScheduler);
假设uiScheduler
是将调用委托给 UI 线程的调度程序,我会说在功能上,使用这两者是无关紧要的(除了对 Control.Invoke 的调用将阻塞直到调用完成,而对Task
的调用不会,但是,您始终可以使用Control.BeginInvoke
使它们在语义上等效)。
从语义的角度来看,我会说使用Control.Invoke(PaintDelegate)
是一种更好的方法; 使用Task
时,您正在隐式声明要执行一个工作单元,通常,该工作单元具有与其他工作单元一起调度的上下文,它是调度程序决定如何委派该工作(通常,它是多线程的,但在这种情况下,它被编组到 UI 线程)。 还应该说, uiScheduler
和与应该进行调用的 UI 线程相关联的Control
之间没有明确的联系(通常,它们都是相同的,但是可以有多个 UI 线程,尽管非常稀有)。
但是,在使用Control.Invoke
时,您想要做的事情的意图很明确,您希望将调用编组到Control
正在泵送消息的 UI 线程,并且此调用完美地表明了这一点。
然而,我认为最好的选择是使用SynchronizationContext
实例; 它抽象出您需要将调用同步到该上下文的事实,而不是其他两个选项,这两个选项要么对调用中的意图模棱两可( Task
),要么在完成方式上非常具体( Control.Invoke
)。
不一样。 第一个版本将阻塞调用线程,直到 UI 线程准备好调用该方法。 对于非阻塞版本,您应该使用Control.BeginInvoke
,它也会立即返回。
除此之外(如果您将任务与线程池线程进行比较),使用它们几乎没有区别。
[编辑]
在这种情况下, Task.Factory.StartNew
和Control.BeginInvoke
之间没有区别(但不是我上面写的Invoke
),因为只有一个 GUI 线程可以执行您的代码。 无论您使用其中任何一个调用多少次,当 UI 线程空闲时,它们仍将按顺序执行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.