使用TaskScheduler控制.Invoke与任务

时间:2011-04-28 12:04:11

标签: c# multithreading task

我看了一遍,我找不到答案。 使用是否更好,更糟或无动于衷:

{
...
RefreshPaintDelegate PaintDelegate = new RefreshPaintDelegate(RefreshPaint);
Control.Invoke(PaintDelegate);
}

protected void RefreshPaint()
{
    this.Refresh();
}

...或...

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

2 个答案:

答案 0 :(得分:3)

假设uiScheduler是一个将委托调用到UI线程的调度程序,我会说在功能上,使用这两个是无关紧要的(除了对Control.Invoke的调用将阻塞直到调用完成,而对Task的调用不会,但是,您始终可以使用Control.BeginInvoke使它们在语义上等效。

从语义的角度来看,我会说使用Control.Invoke(PaintDelegate)是一种更好的方法;当你使用Task时,你正在做一个隐含的声明,你想要执行一个工作单元,并且通常,该工作单元具有与其他工作单元一起安排的上下文,它是决定如何工作的调度程序该工作是委派的(通常,它是多线程的,但在这种情况下,它被封送到UI线程)。还应该说,uiSchedulerControl之间没有明确的联系,它与UI线程相关联,调用应该是一个(通常,它们都是相同的,但它是可能有多个UI线程,虽然非常罕见)。

但是,在使用Control.Invoke时,您想要做的意图是明确的,您想要调用Control正在为消息打开的UI线程的调用,并且此调用指示那很完美。

但我认为最好的选择是使用SynchronizationContext实例;它抽象出你需要同步调用该上下文的事实,而不是其他两个选项,这两个选项要么对调用中的意图不明确(Task),要么非常具体地说明它的完成方式(Control.Invoke)。

答案 1 :(得分:0)

不一样。第一个版本将阻止调用线程,直到UI线程准备好调用该方法。对于非阻止版本,您应该使用Control.BeginInvoke,它也会立即返回。

除此之外(如果您将Task与线程池线程进行比较),使用它们几乎没有区别。

[编辑]

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