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).
From a semantic point of view, I'd say that using Control.Invoke(PaintDelegate)
is a much better approach; 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). 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).
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.
I think the best option, however, is to use a SynchronizationContext
instance; 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
).
It is not same. First version will block the calling thread until UI thread is ready to invoke the method. For a non blocking version, you should use Control.BeginInvoke
, which also returns immediately.
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. No matter how many calls you make using either of them, they will still execute sequentially when UI thread becomes free.
精彩评论