简体   繁体   English

使用 TaskScheduler 的 Control.Invoke 与任务

[英]Control.Invoke vs Tasks with a TaskScheduler

I've looked all over and I can't find an answer.我已经看遍了,我找不到答案。 Is it better, worse, or indifferent to use:使用它是更好、更坏还是无所谓:

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

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

...or... ...或者...

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

Assuming that uiScheduler is a scheduler that will delegate the calls to the UI thread, I would say that functionally, using the two is indifferent (with the exception that the call to Control.Invoke will block until the call completes, whereas the call to Task will not, however, you can always use Control.BeginInvoke to make them semantically equivalent).假设uiScheduler是将调用委托给 UI 线程的调度程序,我会说在功能上,使用这两者是无关紧要的(除了对 Control.Invoke 的调用将阻塞直到调用完成,而对Task的调用不会,但是,您始终可以使用Control.BeginInvoke使它们在语义上等效)。

From a semantic point of view, I'd say that using Control.Invoke(PaintDelegate) is a much better approach;从语义的角度来看,我会说使用Control.Invoke(PaintDelegate)是一种更好的方法; when using a Task you are making an implicit declaration that you want to perform a unit of work, and typically, that unit of work has the context of being scheduled along with other units of work, it's the scheduler that determines how that work is delegated (typically, it's multi-threaded, but in this case, it's marshaled to the UI thread).使用Task时,您正在隐式声明要执行一个工作单元,通常,该工作单元具有与其他工作单元一起调度的上下文,它是调度程序决定如何委派该工作(通常,它是多线程的,但在这种情况下,它被编组到 UI 线程)。 It should also be said that there is no clear link between the uiScheduler and the Control which is linked to the UI thread that the call should be made one (typically, they are all the same, but it's possible to have multiple UI threads, although very rare).还应该说, uiScheduler和与应该进行调用的 UI 线程相关联的Control之间没有明确的联系(通常,它们都是相同的,但是可以有多个 UI 线程,尽管非常稀有)。

However, in using Control.Invoke , the intention of what you want to do is clear, you want to marshal the call to the UI thread that the Control is pumping messages on, and this call indicates that perfectly.但是,在使用Control.Invoke时,您想要做的事情的意图很明确,您希望将调用编组到Control正在泵送消息的 UI 线程,并且此调用完美地表明了这一点。

I think the best option, however, is to use a SynchronizationContext instance;然而,我认为最好的选择是使用SynchronizationContext实例; it abstracts out the fact that you need to synchronize calls to that context, as opposed to the other two options, which are either ambiguous about the intent in the call ( Task ) or very specific in the way it is being done ( Control.Invoke ).它抽象出您需要将调用同步到该上下文的事实,而不是其他两个选项,这两个选项要么对调用中的意图模棱两可( Task ),要么在完成方式上非常具体( Control.Invoke )。

It is not same.不一样。 First version will block the calling thread until UI thread is ready to invoke the method.第一个版本将阻塞调用线程,直到 UI 线程准备好调用该方法。 For a non blocking version, you should use Control.BeginInvoke , which also returns immediately.对于非阻塞版本,您应该使用Control.BeginInvoke ,它也会立即返回。

Apart from that (if you are comparing Task to a Thread Pool thread), there is little difference in using them.除此之外(如果您将任务与线程池线程进行比较),使用它们几乎没有区别。

[Edit] [编辑]

In this case, there is no difference between Task.Factory.StartNew and Control.BeginInvoke (but not Invoke as I wrote above), since there is only a single GUI thread which can execute your code.在这种情况下, Task.Factory.StartNewControl.BeginInvoke之间没有区别(但不是我上面写的Invoke ),因为只有一个 GUI 线程可以执行您的代码。 No matter how many calls you make using either of them, they will still execute sequentially when UI thread becomes free.无论您使用其中任何一个调用多少次,当 UI 线程空闲时,它们仍将按顺序执行。

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

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