Control.Invoke vs Tasks with a TaskScheduler

本文关键字:TaskScheduler with Tasks Invoke vs Control | 更新日期: 2023-09-27 17:53:46

我看遍了,找不到答案。使用是更好、更差还是无动于衷:

{
...
RefreshPaintDelegate PaintDelegate = new RefreshPaintDelegate(RefreshPaint);
Control.Invoke(PaintDelegate);
}
protected void RefreshPaint()
{
    this.Refresh();
}

。或。。。

Task.Factory.StartNew(() =>
{
    this.Refresh();
},
CancellationToken.None,
TaskCreationOptions.None,
uiScheduler);

Control.Invoke vs Tasks with a TaskScheduler

假设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 与线程池线程进行比较(,使用它们几乎没有区别。

[编辑]

在这种情况下,Task.Factory.StartNewControl.BeginInvoke 之间没有区别(但不是我上面写的Invoke(,因为只有一个 GUI 线程可以执行您的代码。无论您使用它们中的任何一个进行多少次调用,当 UI 线程变为空闲时,它们仍将按顺序执行。