Control.Invoke与具有TaskScheduler的任务
我已经看遍了所有,我找不到答案。 是更好,更糟糕的,或漠不关心的使用方法:Control.Invoke与具有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
和Control
之间没有明确的联系,链接到UI线程,应该调用一个线程(通常,它们都是相同的,但可能有多个UI线程,尽管很稀少)。
但是,在使用Control.Invoke
时,您想要执行的操作的意图很明确,您希望将呼叫整理到Control
正在抽取消息的UI线程,并且此调用完全表明。
但我认为最好的选择是使用SynchronizationContext
实例;它抽象出您需要将呼叫同步到该上下文的事实,而不是其他两个选项,这些选项对呼叫中的意图(Task
)或对于它的完成方式非常具体(Control.Invoke
)不明确。
这是不一样的。第一个版本将阻止调用线程,直到UI线程准备调用该方法。对于非阻塞版本,您应该使用Control.BeginInvoke
,它也会立即返回。
除此之外(如果您将任务与线程池线程进行比较),使用它们几乎没有什么区别。
[编辑]
在这种情况下,存在Task.Factory.StartNew
和Control.BeginInvoke
(但不Invoke
正如我上面写)之间没有差别,因为只有一个单一的GUI线程可以执行代码。无论您使用其中任何一个进行了多少次调用,它们仍将在UI线程变为空闲时依次执行。
但是['BeginInvoke'](http://msdn.microsoft.com/en-us/library/system.windows.forms.control.begininvoke.aspx)不会。与“Invoke”相同的语法,但它是异步的。 – 2011-04-28 12:07:48
查看更多信息,请参阅[Invoke()和BeginInvoke()](http://stackoverflow.com/q/229554/616329)之间的区别。 – 2011-04-28 12:10:43
所以Task.Factory.StartNew()会更加开放并行吗?它会安排刷新发生,并允许调用线程继续,对不对? – 2011-04-28 12:10:48