Introduction
As the word Yield
means, the Yield()
method transfers the execution right of the current task, after that other tasks may get the right to execute. And the method of Yield()
is existed in Task
, Dispatcher
, Thread
class, and as the name shows, all of these methods are to transfer the current task’s execution right.
Are there any differences? How do they work?
In this article, we will see more details about the Yield()
methods.
Details
The original link is 出让执行权:Task.Yield, Dispatcher.Yield. But this blog was written in Chinese, so I translate its content to English. Waterlv is an MVP(Microsoft Most Valuable Professional), and he is good at .NET Core\WPF\.NET. Here is his Blog.
Dispatcher.Yield
If we have to implement a time-consuming method, what methods or API
will you choose to avoid affecting the UI
thread? Maybe Invoke
and InvokeAsync
is a good choice, they split the time-consuming task into small pieces that are executed at a lower priority than user input and rendering.
Dispatcher.Yield()
does the same job, and its function is more familiar with Dispatcher.InvokeAsync
than Dispatcher.Invoke
.
It needs await
before the method when we use it.
1 | foreach(var item in collection) |
As the codes above, it splits the task to small pieces every time when executing foreach
method. Therefore, the UI
thread can respond to user interaction and rendering when running these time-consuming codes.
We can pass a parameter to Yield
method when we use it, the value of this parameter is the priority of the subsequent task. Its default value is DispatcherPriority.Background
, and priority of Background
is lower than the user’s input action’s priority (DispatcherPrority.Input
), UI’s priority (DispatcherPriority.Loaded
) and rendering priority (DispatcherPriority.Render
).
How does Dispatcher.Yield
method work?
After reading the source codes of Dispatcher.Yield
, it can find that the result of this method is an instance of DispatcherPriorityAwaiter
, and its OnCompleted
method is posted below.
1 | public void OnCompleted(Action continuation) |
We can find that this OnCompleted
method calls the InvokeAsync
method. It depends on InvokeAsync
to implement its function.
Visit 【C#】【多线程】【05-使用C#6.0】08-自定义awaitable类型 - L.M, for more information about OnCompleted
method.
Tips about Dispatcher.Yield()
Dispatcher.Yield
is a static method of class Dispatcher
, and InvokeAsync
is a normal method.
Here is an example.
1 | using System.Windows.Threading |
Task.Yield
We use Task.Yield
method instead of Dispatcher.Yield
in the example posted above.
1 | foreach(var item in collection) |
This method has the same effect as Dispatcher.Yield(DispatcherPriority.Normal)
. Task
depends on SynchronizationContext
to schedule threads, and the WPF UI thread’s SynchronizationContext
is set to DispatcherSynchronizationContext
, it relies Dispatcher
to schedule; When creating an instance of DispatcherSynchronizationContext
its default priority is Normal
, and WPF doesn’t pass a special value. So, after calling Task.Yield
on WPF UI thread to transfer execution right, it uses Normal
priority to recover. Therefore, its effect is the same as Dispatcher.Yield(DispatcherPriority.Normal)
.
Here is the code about how does DispatcherSynchronizationContext
execute subsequent task.
1 | /// <summary> |
Due to Task.Yield
‘s Normal
priority, its effect on the UI thread is not as good as Dispatcher.Yield
. But, it is important to note that SynchronizationContext
is not related to Dispatcher
, so Task.Yield
can be called on every thread. And it will be a good choice to use Task.Yield
to split the time-consuming task into small tasks in the Task
method.