繁体   English   中英

使用 TaskScheduler 的 Control.Invoke 与任务

[英]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.StartNewControl.BeginInvoke之间没有区别(但不是我上面写的Invoke ),因为只有一个 GUI 线程可以执行您的代码。 无论您使用其中任何一个调用多少次,当 UI 线程空闲时,它们仍将按顺序执行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM