Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
57
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

Chapter 115: Synchronization Context in Async-Await

Section 115.1: Pseudocode for async/await keywords

Consider a simple asynchronous method:

async Task Foo()

{

Bar();

await Baz(); Qux();

}

Simplifying, we can say that this code actually means the following:

Task Foo()

{

Bar();

Task t = Baz();

var context = SynchronizationContext.Current; t.ContinueWith(task) =>

{

if (context == null) Qux();

else

context.Post((obj) => Qux(), null); }, TaskScheduler.Current);

return t;

}

It means that async/await keywords use current synchronization context if it exists. I.e. you can write library code that would work correctly in UI, Web, and Console applications.

Source article.

Section 115.2: Disabling synchronization context

To disable synchronization context you should call the ConfigureAwait method:

async Task() Foo()

{

await Task.Run(() => Console.WriteLine("Test"));

}

. . .

Foo().ConfigureAwait(false);

ConfigureAwait provides a means to avoid the default SynchronizationContext capturing behavior; passing false for the flowContext parameter prevents the SynchronizationContext from being used to resume execution after the await.

GoalKicker.com – C# Notes for Professionals

591

Quote from It's All About the SynchronizationContext.

Section 115.3: Why SynchronizationContext is so important?

Consider this example:

private void button1_Click(object sender, EventArgs e)

{

label1.Text = RunTooLong();

}

This method will freeze UI application until the RunTooLong will be completed. The application will be unresponsive.

You can try run inner code asynchronously:

private void button1_Click(object sender, EventArgs e)

{

Task.Run(() => label1.Text = RunTooLong());

}

But this code won't execute because inner body may be run on non-UI thread and it shouldn't change UI properties directly:

private void button1_Click(object sender, EventArgs e)

{

Task.Run(() =>

{

var label1Text = RunTooLong();

if (label1.InvokeRequired)

lable1.BeginInvoke((Action) delegate() { label1.Text = label1Text; });

else

label1.Text = label1Text;

});

}

Now don't forget always to use this pattern. Or, try SynchronizationContext.Post that will make it for you:

private void button1_Click(object sender, EventArgs e)

{

Task.Run(() =>

{

var label1Text = RunTooLong(); SynchronizationContext.Current.Post((obj) =>

{

label1.Text = label1

Text);

}, null);

 

});

}

GoalKicker.com – C# Notes for Professionals

592