рдирдорд╕реНрдХрд╛рд░, рд╣реЗрдмреНрд░! рдореИрдВ рдЖрдкрдХреЗ рд▓рд┐рдП рд╕реНрдЯреАрдлрди рддрд╛рдЙрдм рджреНрд╡рд╛рд░рд╛ рдХрдиреНрдлрд┐рдЧрд░рдПрд╡рд╛рдЗрдЯ
рдПрдлрдПрдХреНрдпреВ рд▓реЗрдЦ рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реВрдВред

Async
/
Async
рдХреЛ рд╕рд╛рдд рд╕рд╛рд▓ рдкрд╣рд▓реЗ .NET
await
рдЬреЛрдбрд╝рд╛
await
рдерд╛ред рдЗрд╕ рдирд┐рд░реНрдгрдп рдХрд╛ рди рдХреЗрд╡рд▓ .NET рдкрд╛рд░рд┐рд╕реНрдерд┐рддрд┐рдХреА рддрдВрддреНрд░ рдкрд░ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкреНрд░рднрд╛рд╡ рдкрдбрд╝рд╛ рд╣реИ - рдпрд╣ рдХрдИ рдЕрдиреНрдп рднрд╛рд╖рд╛рдУрдВ рдФрд░ рд░реВрдкрд░реЗрдЦрд╛рдУрдВ рдореЗрдВ рднреА рдкрд░рд┐рд▓рдХреНрд╖рд┐рдд рд╣реЛрддрд╛ рд╣реИред рд╡рд░реНрддрдорд╛рди рдореЗрдВ, .NET рдореЗрдВ рдХрдИ рд╕реБрдзрд╛рд░реЛрдВ рдХреЛ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдЕрддрд┐рд░рд┐рдХреНрдд рднрд╛рд╖рд╛ рдирд┐рд░реНрдорд╛рдгреЛрдВ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд╕рдорд░реНрдерди рд╡рд╛рд▓реЗ рдПрдкреАрдЖрдИ рдХреЛ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдмреБрдирд┐рдпрд╛рджреА рдврд╛рдВрдЪреЗ рдореЗрдВ рдореВрд▓рднреВрдд рд╕реБрдзрд╛рд░ рдХрд┐рдП рдЧрдП рд╣реИрдВ рдЬрд┐рд╕рдХреЗ рдХрд╛рд░рдг рдШрдбрд╝реА рдХреА рддрд░рд╣
async
/
await
рдХрд╛рд░реНрдп (рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рдкреНрд░рджрд░реНрд╢рди рдФрд░ рдиреИрджрд╛рдирд┐рдХ тАЛтАЛрдХреНрд╖рдорддрд╛рдУрдВ рдореЗрдВ рд╕реБрдзрд╛рд░ рд╣реБрдЖ рд╣реИ) .NET рдХреЛрд░ рдореЗрдВ)ред
ConfigureAwait
async
/
await
рдХрд╛ рдПрдХ рдкрд╣рд▓реВ рд╣реИ рдЬреЛ рдкреНрд░рд╢реНрди рдЙрдард╛рддрд╛ рд░рд╣рддрд╛ рд╣реИред рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдореИрдВ рдЙрдирдореЗрдВ рд╕реЗ рдХрдИ рдХрд╛ рдЬрд╡рд╛рдм рджреЗ рд╕рдХрддрд╛ рд╣реВрдВред рдореИрдВ рдЗрд╕ рд▓реЗрдЦ рдХреЛ рд╢реБрд░реВ рд╕реЗ рдЕрдВрдд рддрдХ рдкрдардиреАрдп рдмрдирд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛, рдФрд░ рд╕рд╛рде рд╣реА рд╕рд╛рде рдЗрд╕реЗ рдЕрдХреНрд╕рд░ рдкреВрдЫреЗ рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдкреНрд░рд╢реНрдиреЛрдВ (рдПрдлрдПрдХреНрдпреВ) рдХреЗ рдЙрддреНрддрд░ рдХреА рд╢реИрд▓реА рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддрд╛рдХрд┐ рдЗрд╕реЗ рднрд╡рд┐рд╖реНрдп рдореЗрдВ рд╕рдВрджрд░реНрднрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред
рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ
ConfigureAwait
рдирд┐рдкрдЯрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдереЛрдбрд╝рд╛ рдкреАрдЫреЗ рдЬрд╛рдПрдВрдЧреЗред
рдПрдХ рд╕рд┐рдВрдХреНрд░реЛрдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреЙрдирдЯреЗрдХреНрд╕реНрдЯ рдХреНрдпрд╛ рд╣реИ?
System.Threading.SynchronizationContext рдкреНрд░рд▓реЗрдЦрди рдХреЗ рдЕрдиреБрд╕рд╛рд░ "рд╡рд┐рднрд┐рдиреНрди рд╕рд┐рдВрдХреНрд░реЛрдирд╛рдЗрдЬрд╝реЗрд╢рди рдореЙрдбрд▓ рдореЗрдВ рд╕рд┐рдВрдХреНрд░реЛрдирд╛рдЗрдЬрд╝реЗрд╢рди рд╕рдВрджрд░реНрдн рдХреЛ рд╡рд┐рддрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмреБрдирд┐рдпрд╛рджреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред" рдпрд╣ рдкрд░рд┐рднрд╛рд╖рд╛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИред
99.9% рдорд╛рдорд▓реЛрдВ рдореЗрдВ,
SynchronizationContext
рдХреЛ рдПрдХ рдкреНрд░рдХрд╛рд░ рд╕реЗ рд╡рд░реНрдЪреБрдЕрд▓
Post
рд╡рд┐рдзрд┐ рдХреЗ рд╕рд╛рде рдкреНрд░рдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬреЛ рдХрд┐ рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ (
SynchronizationContext
рдореЗрдВ рдЕрдиреНрдп рд╡рд░реНрдЪреБрдЕрд▓ рд╕рджрд╕реНрдп рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╡реЗ рдХрдо рд╕рд╛рдорд╛рдиреНрдп рд╣реИрдВ рдФрд░ рдЗрд╕ рдЖрд▓реЗрдЦ рдореЗрдВ рдЪрд░реНрдЪрд╛ рдирд╣реАрдВ рдХреА рдЬрд╛рдПрдЧреА)ред рдЖрдзрд╛рд░ рдкреНрд░рдХрд╛рд░ рдХреА
Post
рд╡рд┐рдзрд┐ рд╢рд╛рдмреНрджрд┐рдХ
рд░реВрдк рд╕реЗ ThreadPool.QueueUserWorkItem
рдХреЛ
рдХреЙрд▓ рдХрд░рддреА рд╣реИ рддрд╛рдХрд┐ рдкреНрд░рджрд╛рди рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЛ рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рд░реВрдк рд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред рд╡реНрдпреБрддреНрдкрдиреНрди рдкреНрд░рдХрд╛рд░ рдУрд╡рд░рд░рд╛рдЗрдб
Post
рддрд╛рдХрд┐ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рд╕рд╣реА рд╕рдордп рдкрд░ рд╕рд╣реА рдЬрдЧрд╣ рдкрд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░ рд╕рдХреЗред
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, Windows рдкреНрд░рдкрддреНрд░ рдореЗрдВ рдПрдХ SynchronizationContext-рд╡реНрдпреБрддреНрдкрдиреНрди
рдкреНрд░рдХрд╛рд░ рд╣реИ рдЬреЛ
Control.BeginInvoke
рдХреЗ рд╕рдорддреБрд▓реНрдп рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП
Post
рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИред
Control.BeginInvoke
ред рдЗрд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдЗрд╕
Post
рд╡рд┐рдзрд┐ рдХреЗ рд▓рд┐рдП рдХрд┐рд╕реА рднреА рдХреЙрд▓ рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рд╕рдВрдмрдВрдзрд┐рдд рдирд┐рдпрдВрддреНрд░рдг рдХреЗ рд╕рд╛рде рд╕рдВрдмрдВрдзрд┐рдд рдереНрд░реЗрдб рдореЗрдВ рдмрд╛рдж рдХреЗ рдЪрд░рдг рдореЗрдВ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ - рддрдерд╛рдХрдерд┐рдд рдпреВрдЖрдИ рдереНрд░реЗрдбред рд╡рд┐рдВрдбреЛрдЬ рдлреЙрд░реНрдо рдХреЗ рджрд┐рд▓ рдореЗрдВ Win32 рд╕рдВрджреЗрд╢ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рд╣реИред рд╕рдВрджреЗрд╢ рд▓реВрдк рдХреЛ рдПрдХ рдпреВрдЖрдИ рдереНрд░реЗрдб рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬреЛ рдмрд╕ рдирдП рд╕рдВрджреЗрд╢реЛрдВ рдХреЗ рд╕рдВрд╕рд╛рдзрд┐рдд рд╣реЛрдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИред рдпреЗ рд╕рдВрджреЗрд╢ рдорд╛рдЙрд╕ рдореВрд╡рдореЗрдВрдЯ, рдХреНрд▓рд┐рдХ, рдХреАрдмреЛрд░реНрдб рдЗрдирдкреБрдЯ, рд╕рд┐рд╕реНрдЯрдо рдИрд╡реЗрдВрдЯ, рдЬреЛ рдбреЗрд▓рд┐рдЧреЗрдЯреНрд╕ рджреНрд╡рд╛рд░рд╛ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рд╣реИрдВ, рдЖрджрд┐ рджреНрд╡рд╛рд░рд╛ рдЯреНрд░рд┐рдЧрд░ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП, рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ Windows рдлреЙрд░реНрдо рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ UI рдереНрд░реЗрдб рдХреЗ рд▓рд┐рдП рдПрдХ
SynchronizationContext
рдЙрджрд╛рд╣рд░рдг рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдЗрд╕рдореЗрдВ рдСрдкрд░реЗрд╢рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП
Post
рд╡рд┐рдзрд┐ рдореЗрдВ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЛ рдкрд╛рд╕ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
рд╡рд┐рдВрдбреЛрдЬ рдкреНрд░реЗрдЬреЗрдВрдЯреЗрд╢рди рдлрд╝рд╛рдЙрдВрдбреЗрд╢рди (WPF) рдореЗрдВ рдПрдХ рдУрд╡рд░рд░рд╛рдЗрдб
Post
рд╡рд┐рдзрд┐ рдХреЗ рд╕рд╛рде рдПрдХ
SynchronizationContext
рд╡реНрдпреБрддреНрдкрдиреНрди
рдкреНрд░рдХрд╛рд░ рднреА рд╣реИ рдЬреЛ UI рд╕реНрдЯреНрд░реАрдо (
Dispatcher.BeginInvoke
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП) рдХреЛ "рдбрд╛рдпрд░реЗрдХреНрдЯ" рдХрд░рддрд╛ рд╣реИ, WPF рдбрд┐рд╕реНрдкреИрдЪрд░ рдирд┐рдпрдВрддреНрд░рдг рдХреЗ рд╕рд╛рде, рди рдХрд┐ рд╡рд┐рдВрдбреЛрдЬрд╝ рдлреЙрд░реНрдо рдХрдВрдЯреНрд░реЛрд▓ред
рдФрд░ рд╡рд┐рдВрдбреЛрдЬ рд░рдирдЯрд╛рдЗрдо (WinRT) рдХрд╛ рдЕрдкрдирд╛
SynchronizationContext
рд╡реНрдпреБрддреНрдкрдиреНрди
рдкреНрд░рдХрд╛рд░ рд╣реИ , рдЬреЛ
CoreDispatcher
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ UI рдереНрд░реЗрдб
CoreDispatcher
рдореЗрдВ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЛ рднреА рд░рдЦрддрд╛ рд╣реИред
рд╡рд╛рдХреНрдпрд╛рдВрд╢ "UI рдереНрд░реЗрдб рдореЗрдВ рдбреЗрд▓рд┐рдЧреЗрдЯ рд░рди" рдХреЗ рдкреАрдЫреЗ рдпрд╣реА рдирд┐рд╣рд┐рдд рд╣реИред рдЖрдк рдЕрдкрдиреЗ
SynchronizationContext
рдХреЛ
Post
рд╡рд┐рдзрд┐ рдФрд░ рдХреБрдЫ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд╕рд╛рде рднреА рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдореБрдЭреЗ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдЪрд┐рдВрддрд╛ рдХрд░рдиреЗ рдХреА рдЬрд╝рд░реВрд░рдд рдирд╣реАрдВ рд╣реИ рдХрд┐ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХрд┐рд╕ рдереНрд░реЗрдб рдореЗрдВ рдЪрд▓ рд░рд╣рд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдореЗрд░реЗ
SynchronizationContext
рдХреЙрдиреНрдЯреЗрдХреНрд╕реНрдЯ рдореЗрдВ рдХреЛрдИ рднреА
Post
рдкрджреНрдзрддрд┐ рдбреЗрд▓рд┐рдЧреЗрдЯ рдХреЗ рдХреБрдЫ рд╕реАрдорд┐рдд рдбрд┐рдЧреНрд░реА рдХреЗ рд╕рд╛рде рдЪрд▓реЗред рдЖрдк рдЗрд╕ рддрд░рд╣ рд╕реЗ рдПрдХ рдХрд╕реНрдЯрдо
SynchronizationContext
рдХреЛ рд▓рд╛рдЧреВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
internal sealed class MaxConcurrencySynchronizationContext : SynchronizationContext { private readonly SemaphoreSlim _semaphore; public MaxConcurrencySynchronizationContext(int maxConcurrencyLevel) => _semaphore = new SemaphoreSlim(maxConcurrencyLevel); public override void Post(SendOrPostCallback d, object state) => _semaphore.WaitAsync().ContinueWith(delegate { try { d(state); } finally { _semaphore.Release(); } }, default, TaskContinuationOptions.None, TaskScheduler.Default); public override void Send(SendOrPostCallback d, object state) { _semaphore.Wait(); try { d(state); } finally { _semaphore.Release(); } } }
XUnit рдврд╛рдВрдЪреЗ рдореЗрдВ SynchronizationContext
рдХрд╛ рд╕рдорд╛рди
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИ ред рдпрд╣рд╛рдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╕рдорд╛рдирд╛рдВрддрд░ рдкрд░реАрдХреНрд╖рдгреЛрдВ рд╕реЗ рдЬреБрдбрд╝реЗ рдХреЛрдб рдХреА рдорд╛рддреНрд░рд╛ рдХреЛ рдХрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рдпрд╣рд╛рдВ рдлрд╛рдпрджреЗ рдХрд┐рд╕реА рднреА рдЕрдореВрд░реНрдд рдХреЗ рд╕рд╛рде рд╕рдорд╛рди рд╣реИрдВ: рдПрдХ рдПрдХрд▓ рдПрдкреАрдЖрдИ рдкреНрд░рджрд╛рди рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд┐рд╡рд░рдг рдХреЛ рдЬрд╛рдирдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдмрд┐рдирд╛, рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреА рдЗрдЪреНрдЫрд╛рдиреБрд╕рд╛рд░ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рд▓рд┐рдП рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЛ рдХрддрд╛рд░ рдореЗрдВ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдорд╛рди рд▓реАрдЬрд┐рдП рдореИрдВ рдПрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд▓рд┐рдЦрддрд╛ рд╣реВрдБ рдЬрд╣рд╛рдБ рдореБрдЭреЗ рдХреБрдЫ рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдЬрд╝рд░реВрд░рдд рд╣реЛрддреА рд╣реИ рдФрд░ рдлрд┐рд░ рдПрдХ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЛ рдореВрд▓ рд╕рдВрджрд░реНрдн рдореЗрдВ рд╡рд╛рдкрд╕ рднреЗрдЬрдирд╛ рдЪрд╛рд╣рд┐рдПред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореБрдЭреЗ рдЗрд╕рдХреЗ
SynchronizationContext
рдкрд░ рдХрдмреНрдЬрд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдФрд░ рдЬрдм рдореБрдЭреЗ рдкреВрд░рд╛ рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рддреЛ рдореБрдЭреЗ рдЗрд╕ рд╕рдВрджрд░реНрдн рдХреА
Post
рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдЗрд╕реЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЛ рдкрд╛рд╕ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдореБрдЭреЗ рдпрд╣ рдЬрд╛рдирдиреЗ рдХреА рдЬрд░реВрд░рдд рдирд╣реАрдВ рд╣реИ рдХрд┐ рд╡рд┐рдВрдбреЛрдЬ рдлреЙрд░реНрдо рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ
Dispatcher
рд╕реЗ
BeginInvoke
рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП
Control
рдФрд░ рдЗрд╕рдХреЗ
BeginInvoke
рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдпрд╛ рдХрд┐рд╕реА рддрд░рд╣ рдПрдХреНрд╕рдпреВрдирд╛рдЗрдЯ рдХреЗ рд▓рд┐рдП рд╕рдВрджрд░реНрдн рдФрд░ рдЗрд╕рдХреА рдХрддрд╛рд░ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред рдореБрдЭреЗ рдХреЗрд╡рд▓ рд╡рд░реНрддрдорд╛рди
SynchronizationContext
рдХреЛ рд╣рдерд┐рдпрд╛рдиреЗ рдФрд░ рдмрд╛рдж рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП,
SynchronizationContext
рдореЗрдВ
Current
рдЧреБрдг рд╣реЛрддрд╛ рд╣реИред рдЗрд╕реЗ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
public void DoWork(Action worker, Action completion) { SynchronizationContext sc = SynchronizationContext.Current; ThreadPool.QueueUserWorkItem(_ => { try { worker(); } finally { sc.Post(_ => completion(), null); } }); }
рдЖрдк
SynchronizationContext.SetSynchronizationContext
рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ
Current
рд╕рдВрдкрддреНрддрд┐ рд╕реЗ рдПрдХ рд╡рд┐рд╢реЗрд╖ рд╕рдВрджрд░реНрдн рд╕реЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдХрд╛рд░реНрдп рдЕрдиреБрд╕реВрдЪрдХ рдХреНрдпрд╛ рд╣реИ?
SynchronizationContext
"рдЕрдиреБрд╕реВрдЪрдХ" рдХреЗ рд▓рд┐рдП рдПрдХ рдЖрдо рдЕрдореВрд░реНрдд рд╣реИред рдХреБрдЫ рдврд╛рдВрдЪреЗ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдЕрдореВрд░реНрдд рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░
System.Threading.Tasks
рдХреЛрдИ рдЕрдкрд╡рд╛рдж рдирд╣реАрдВ рд╣реИред рдЬрдм
Task
рдореЗрдВ рдкреНрд░рддрд┐рдирд┐рдзрд┐рдпреЛрдВ рдХреЛ рдХрддрд╛рд░рдмрджреНрдз рдФрд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рддреЛ рд╡реЗ
System.Threading.Tasks.TaskScheduler
рдХреЗ рд╕рд╛рде рдЬреБрдбрд╝реЗ рд╣реЛрддреЗ рд╣реИрдВред рдПрдХ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЛ рдкрдВрдХреНрддрд┐рдмрджреНрдз рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЖрднрд╛рд╕реА
Post
рд╡рд┐рдзрд┐ рднреА рд╣реИ (рдорд╛рдирдХ рддрдВрддреНрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЙрд▓ рдХреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ),
TaskScheduler
рдПрдХ рд╕рд╛рд░
QueueTask
рд╡рд┐рдзрд┐ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ (
QueueTask
рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдХрд╛рд░реНрдп рдХреЙрд▓ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛
ExecuteTask
рд╣реИ)ред
рдХрд╛рд░реНрдп рд╢реЗрдбреНрдпреВрд▓рд░
TaskScheduler.Default
рдХреЛ рд▓реМрдЯрд╛рдиреЗ
TaskScheduler.Default
рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╢реЗрдбреНрдпреВрд▓рд░ рдПрдХ рдереНрд░реЗрдб рдкреВрд▓ рд╣реИред
TaskScheduler
рд╕реЗ
Task
рдХреЙрд▓ рдХреЗ рд╕рдордп рдФрд░ рд╕реНрдерд╛рди рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЛрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдФрд░ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдирд╛ рднреА рд╕рдВрднрд╡ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдХреЛрд░ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдореЗрдВ
System.Threading.Tasks.ConcurrentExclusiveSchedulerPair
рдЯрд╛рдЗрдк рд╣реЛрддрд╛ рд╣реИред рдЗрд╕ рд╡рд░реНрдЧ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджреЛ
TaskScheduler
рдЧреБрдг рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ:
ExclusiveScheduler
рдФрд░
TaskScheduler
ред
ConcurrentScheduler
рдореЗрдВ рд╢реЗрдбреНрдпреВрд▓ рдХрд┐рдП рдЧрдП рдХрд╛рд░реНрдп рд╕рдорд╛рдирд╛рдВрддрд░ рдореЗрдВ рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЬрдм рдпрд╣ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (
MaxConcurrencySynchronizationContext
рд╕рдорд╛рди)
ConcurrentExclusiveSchedulerPair
рджреНрд╡рд╛рд░рд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдкреНрд░рддрд┐рдмрдВрдз рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрддреЗ рд╣реБрдПред рдпрджрд┐
ExclusiveScheduler
рдореЗрдВ рдХрд╛рд░реНрдп рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдХреЛрдИ
ConcurrentScheduler
рдХрд╛рд░реНрдп рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдФрд░ рдХреЗрд╡рд▓ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдХрд╛рд░реНрдп рдХреЛ рдПрдХ рд╕рдордп рдореЗрдВ рдЪрд▓рд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рд╣реИред рдпрд╣ рд╡реНрдпрд╡рд╣рд╛рд░ рдмрд╣реБрдд рдХреБрдЫ рдкрдврд╝рдиреЗ / рд▓рд┐рдЦрдиреЗ рдХреЗ рддрд╛рд▓рд╛ рдХреЗ рд╕рдорд╛рди рд╣реИред
SynchronizationContext
TaskScheduler
рдХреА рддрд░рд╣,
TaskScheduler
рдореЗрдВ рдПрдХ
Current
рдкреНрд░реЙрдкрд░реНрдЯреА рд╣реЛрддреА рд╣реИ рдЬреЛ рдХрд░рдВрдЯ
TaskScheduler
рд╡рд╛рдкрд╕
TaskScheduler
ред рд╣рд╛рд▓рд╛рдБрдХрд┐,
SynchronizationContext
рд╡рд┐рдкрд░реАрдд, рдЗрд╕рдореЗрдВ рд╡рд░реНрддрдорд╛рди рдЕрдиреБрд╕реВрдЪрдХ рдХреЛ рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рдзрд┐ рдХрд╛ рдЕрднрд╛рд╡ рд╣реЛрддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, рд╢реЗрдбреНрдпреВрд▓рд░ рд╡рд░реНрддрдорд╛рди рдХрд╛рд░реНрдп рдХреЗ рд╕рд╛рде рдЬреБрдбрд╝рд╛ рд╣реБрдЖ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ рдкреНрд░реЛрдЧреНрд░рд╛рдо
True
рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐
StartNew
рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рд▓реИрдореНрдмреНрдбрд╛ рдХреЛ
ConcurrentExclusiveSchedulerPair
рдХреЗ
ExclusiveScheduler
рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░
TaskScheduler.Current
рдЗрд╕ рдЕрдиреБрд╕реВрдЪрдХ рдкрд░ рд╕реНрдерд╛рдкрд┐рдд рд╣реЛрддрд╛ рд╣реИ:
using System; using System.Threading.Tasks; class Program { static void Main() { var cesp = new ConcurrentExclusiveSchedulerPair(); Task.Factory.StartNew(() => { Console.WriteLine(TaskScheduler.Current == cesp.ExclusiveScheduler); }, default, TaskCreationOptions.None, cesp.ExclusiveScheduler).Wait(); } }
рджрд┐рд▓рдЪрд╕реНрдк рдмрд╛рдд рдпрд╣ рд╣реИ рдХрд┐
TaskScheduler
рдПрдХ рд╕реНрдерд┐рд░
FromCurrentSynchronizationContext
рд╡рд┐рдзрд┐ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдпрд╣ рд╡рд┐рдзрд┐ рдПрдХ рдирдпрд╛
TaskScheduler
рдФрд░ рдпрд╣
Post
рдкрджреНрдзрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓реМрдЯреЗ
SynchronizationContext.Current
рдХреЙрдиреНрдЯреЗрдХреНрд╕реНрдЯ.рдХрдВрдЯрд░реНрдирд▓ рд╕рдВрджрд░реНрдн рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдпреЛрдВ рдХреЛ
TaskScheduler
рдХрд░рддреА рд╣реИред
SynchronizationContext рдФрд░ TaskScheduler рдХреИрд╕реЗ рдкреНрд░рддреАрдХреНрд╖рд╛ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реИрдВ?
рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рдЖрдкрдХреЛ рдПрдХ рдмрдЯрди рдХреЗ рд╕рд╛рде рдПрдХ рдпреВрдЖрдИ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд▓рд┐рдЦрдирд╛ рд╣реИред рдмрдЯрди рджрдмрд╛рдиреЗ рд╕реЗ рд╡реЗрдмрд╕рд╛рдЗрдЯ рд╕реЗ рдЯреЗрдХреНрд╕реНрдЯ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдирд╛ рд╢реБрд░реВ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдпрд╣
Content
рдмрдЯрди рдкрд░ рд╕реЗрдЯ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рдмрдЯрди рдХреЗрд╡рд▓ рдЙрд╕ рд╕реНрдЯреНрд░реАрдо рдХреЗ UI рд╕реЗ рд╕реБрд▓рдн рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдЬрд┐рд╕рдореЗрдВ рд╡рд╣ рд╕реНрдерд┐рдд рд╣реИ, рдЗрд╕рд▓рд┐рдП, рдЬрдм рд╣рдо рджрд┐рдирд╛рдВрдХ рдФрд░ рд╕рдордп рдХреЛ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рд▓реЛрдб рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдмрдЯрди рдХреА
Content
рдореЗрдВ рд░рдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ рдЙрд╕ рд╕реНрдЯреНрд░реАрдо рд╕реЗ рдпрд╣ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЙрд╕ рдкрд░ рдирд┐рдпрдВрддреНрд░рдг рд╣реИред рдпрджрд┐ рдпрд╣ рд╢рд░реНрдд рдкреВрд░реА рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ, рддреЛ рд╣рдореЗрдВ рдПрдХ рдЕрдкрд╡рд╛рдж рдорд┐рд▓реЗрдЧрд╛:
System.InvalidOperationException: ' , .'
рд╣рдо
Content
рдХреЛ рд╕реНрд░реЛрдд рд╕рдВрджрд░реНрдн рдореЗрдВ рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП
SynchronizationContext
TaskScheduler
рдЙрдкрдпреЛрдЧ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП
TaskScheduler
рдорд╛рдзреНрдпрдо рд╕реЗ:
private static readonly HttpClient s_httpClient = new HttpClient(); private void downloadBtn_Click(object sender, RoutedEventArgs e) { s_httpClient.GetStringAsync("http://example.com/currenttime").ContinueWith(downloadTask => { downloadBtn.Content = downloadTask.Result; }, TaskScheduler.FromCurrentSynchronizationContext()); }
рдФрд░ рд╣рдо рд╕реАрдзреЗ
SynchronizationContext
рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
private static readonly HttpClient s_httpClient = new HttpClient(); private void downloadBtn_Click(object sender, RoutedEventArgs e) { SynchronizationContext sc = SynchronizationContext.Current; s_httpClient.GetStringAsync("http://example.com/currenttime").ContinueWith(downloadTask => { sc.Post(delegate { downloadBtn.Content = downloadTask.Result; }, null); }); }
рд╣рд╛рд▓рд╛рдБрдХрд┐, рдпреЗ рджреЛрдиреЛрдВ рд╡рд┐рдХрд▓реНрдк рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдХреЙрд▓рдмреИрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, рд╣рдо
async
/
await
рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
private static readonly HttpClient s_httpClient = new HttpClient(); private async void downloadBtn_Click(object sender, RoutedEventArgs e) { string text = await s_httpClient.GetStringAsync("http://example.com/currenttime"); downloadBtn.Content = text; }
рдпрд╣ рд╕рдм "рдмрд╕ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ" рдФрд░ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдпреВрдЖрдИ рдереНрд░реЗрдб рдореЗрдВ
Content
рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд┐рдП рдЧрдП рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдирд╛
SynchronizationContext.Current
TaskScheduler.Current
рдФрд░
TaskScheduler.Current
рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддрд╛ рд╣реИред рдЬрдм рдЖрдк C # рдореЗрдВ рдХреБрдЫ "рдЙрдореНрдореАрдж" рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╕рдВрдХрд▓рдХ рдорддрджрд╛рди рдХреЗ рд▓рд┐рдП рдХреЛрдб рдХреЛ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рддрд╛ рд╣реИ (
GetAwaiter
рдХреЛ рдХреЙрд▓
GetAwaiter
) "рдЕрдкреЗрдХреНрд╖рд┐рдд" (рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдХрд╛рд░реНрдп) рдХреЛ "рдкреНрд░рддреАрдХреНрд╖рд╛" (
TaskAwaiter
)ред "рдкреНрд░рддреАрдХреНрд╖рд╛" рдХреЙрд▓рдмреИрдХ рд╕рдВрд▓рдЧреНрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд╝рд┐рдореНрдореЗрджрд╛рд░ рд╣реИ (рдЬрд┐рд╕реЗ рдЕрдХреНрд╕рд░ "рдирд┐рд░рдВрддрд░рддрд╛" рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ) рдЬреЛ рдкреНрд░рддреАрдХреНрд╖рд╛ рдкреВрд░реА рд╣реЛрдиреЗ рдкрд░ рд░рд╛рдЬреНрдп рдорд╢реАрди рдХреЛ рд╡рд╛рдкрд╕ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИред рд╡рд╣ рдХреЙрд▓рдмреИрдХ рдкрдВрдЬреАрдХрд░рдг рдХреЗ рджреМрд░рд╛рди рдХреИрдкреНрдЪрд░ рдХрд┐рдП рдЧрдП рд╕рдВрджрд░реНрдн / рдЕрдиреБрд╕реВрдЪрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕реЗ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИред рд╣рдо рдЗрд╕реЗ рдереЛрдбрд╝рд╛ рдЕрдиреБрдХреВрд▓рд┐рдд рдФрд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВрдЧреЗ, рдпрд╣ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рд╣реИ:
object scheduler = SynchronizationContext.Current; if (scheduler is null && TaskScheduler.Current != TaskScheduler.Default) { scheduler = TaskScheduler.Current; }
рдпрд╣рд╛рдВ, рдпрд╣ рдкрд╣рд▓реЗ рдЪреЗрдХ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐
SynchronizationContext
TaskScheduler
SynchronizationContext
, рдФрд░ рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рдХреНрдпрд╛ рдХреЛрдИ рдЧреИрд░-рдорд╛рдирдХ
TaskScheduler
ред рдпрджрд┐ рдПрдХ рд╣реИ, рддреЛ рдЬрдм рдХреЙрд▓рдмреИрдХ рдХреЙрд▓ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИ, рддреЛ рдХреИрдкреНрдЪрд░ рдХрд┐рдП рдЧрдП рд╢реЗрдбреНрдпреВрд▓рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛; рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рдХреЙрд▓рдмреИрдХ рдСрдкрд░реЗрд╢рди рдХреЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рд░реВрдк рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдЬреЛ рдЕрдкреЗрдХреНрд╖рд┐рдд рдХрд╛рд░реНрдп рдкреВрд░рд╛ рдХрд░рддрд╛ рд╣реИред
рдХреЙрдиреНрдлрд╝рд┐рдЧрд░рд╡рд┐рдЯ рдХреНрдпрд╛ рдХрд░рддрд╛ рд╣реИ (рдЭреВрдард╛)
ConfigureAwait
рд╡рд┐рдзрд┐ рд╡рд┐рд╢реЗрд╖ рдирд╣реАрдВ рд╣реИ: рдпрд╣ рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рддрд░реАрдХреЗ рд╕реЗ рд╕рдВрдХрд▓рдХ рдпрд╛ рд░рдирдЯрд╛рдЗрдо рджреНрд╡рд╛рд░рд╛ рдорд╛рдиреНрдпрддрд╛ рдкреНрд░рд╛рдкреНрдд рдирд╣реАрдВ рд╣реИред рдпрд╣ рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рд╡рд┐рдзрд┐ рд╣реИ рдЬреЛ рдПрдХ рд╕рдВрд░рдЪрдирд╛ рд▓реМрдЯрд╛рддрд╛ рд╣реИ (
ConfiguredTaskAwaitable
- рдореВрд▓ рдХрд╛рд░реНрдп рдХреЛ рд▓рдкреЗрдЯрддрд╛ рд╣реИ) рдФрд░ рдмреВрд▓рд┐рдпрди рдорд╛рди рд▓реЗрддрд╛ рд╣реИред рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐
await
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рд╕реА рднреА рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рд╛рде рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдЬреЛ рд╕рд╣реА рдкреИрдЯрд░реНрди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рджреВрд╕рд░рд╛ рдкреНрд░рдХрд╛рд░ рд▓реМрдЯрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдЬрдм рд╕рдВрдХрд▓рдХ рдХреЛ
GetAwaiter
рд╡рд┐рдзрд┐ (рдкреИрдЯрд░реНрди рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛) рдХрд╛ рдЙрдкрдпреЛрдЧ рдкреНрд░рд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХреНрдпрд╛ рдпрд╣
ConfigureAwait
рдкреНрд░рдХрд╛рд░ рд╕реЗ рд▓реМрдЯрд╛рдП рдЧрдП рдкреНрд░рдХрд╛рд░ рд╕реЗ рд╣реИ, рдФрд░ рд╕реАрдзреЗ рдХрд╛рд░реНрдп рд╕реЗ рдирд╣реАрдВред рдпрд╣ рдЖрдкрдХреЛ рдЗрд╕ рд╡рд┐рд╢реЗрд╖ рд╡реЗрдЯрд░ рдХреЗ рд▓рд┐рдП
await
рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред
ConfigureAwait(continueOnCapturedContext: false)
рджреНрд╡рд╛рд░рд╛ рд▓реМрдЯрд╛рдП рдЧрдП рдкреНрд░рдХрд╛рд░ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп
Task
рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рд╕реЗ рд╕реАрдзреЗ рдКрдкрд░ рдЪрд░реНрдЪрд╛ рдХреА рдЧрдИ рд╕рдВрджрд░реНрдн / рдЕрдиреБрд╕реВрдЪрдХ рдХреИрдкреНрдЪрд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкреНрд░рднрд╛рд╡рд┐рдд рд╣реЛрддрд╛ рд╣реИред рддрд░реНрдХ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рдмрдирддрд╛ рд╣реИ:
object scheduler = null; if (continueOnCapturedContext) { scheduler = SynchronizationContext.Current; if (scheduler is null && TaskScheduler.Current != TaskScheduler.Default) { scheduler = TaskScheduler.Current; } }
рджреВрд╕рд░реЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ,
false
рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддреЗ
false
, рднрд▓реЗ рд╣реА рдХреЙрд▓рдмреИрдХ рдХреЗ рд▓рд┐рдП рд╡рд░реНрддрдорд╛рди рд╕рдВрджрд░реНрдн рдпрд╛ рд╢реЗрдбреНрдпреВрд▓рд░ рд╣реЛ, рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдпрд╣ рдЕрдиреБрдкрд╕реНрдерд┐рдд рд╣реИред
рдореБрдЭреЗ рдХрдиреНрдлрд┐рдЧрд░рдПрд╡рд┐рдЯ (рдЧрд▓рдд) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реИ?
ConfigureAwait(continueOnCapturedContext: false)
рдЙрдкрдпреЛрдЧ рдХреЙрд▓рдмреИрдХ рдХреЛ рд╕реНрд░реЛрдд рд╕рдВрджрд░реНрдн рдпрд╛ рд╢реЗрдбреНрдпреВрд▓рд░ рдореЗрдВ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рдХрд░рдиреЗ рд╕реЗ рд░реЛрдХрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕рд╕реЗ рд╣рдореЗрдВ рдХрдИ рдлрд╛рдпрджреЗ рдорд┐рд▓рддреЗ рд╣реИрдВ:
рдкреНрд░рджрд░реНрд╢рди рдореЗрдВ рд╕реБрдзрд╛рд░ред рдХреЙрд▓рд┐рдВрдЧ рдХреЛ рдкрдВрдХреНрддрд┐рдмрджреНрдз рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдУрд╡рд░рд╣реЗрдб рд╣реИ, рдХреЗрд╡рд▓ рдХреЙрд▓рд┐рдВрдЧ рдХреЗ рд╡рд┐рдкрд░реАрдд, рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЕрддрд┐рд░рд┐рдХреНрдд рдХрд╛рдо (рдФрд░ рдЖрдорддреМрд░ рдкрд░ рдЕрддрд┐рд░рд┐рдХреНрдд рдЖрд╡рдВрдЯрди) рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдо рд░рдирдЯрд╛рдЗрдо рдореЗрдВ рдЕрдиреБрдХреВрд▓рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рд╣рдо рдЕрдзрд┐рдХ рдЕрдиреБрдХреВрд▓рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬрдм рд╣рдо рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдХреЙрд▓рдмреИрдХ рдХреИрд╕реЗ рдХрд╣рд╛ рдЬрд╛рдПрдЧрд╛, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдпрд╣ рдЕрдореВрд░реНрдд рдХреЗ рдордирдорд╛рдиреЗ рдврдВрдЧ рд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдкрд╛рд░рд┐рдд рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдХрднреА-рдХрднреА рдпрд╣ рдкреНрд░рддрд┐рдмрдВрдз рд▓рдЧрд╛рддрд╛ рд╣реИ)ред рднрд╛рд░реА рд▓реЛрдб рд╡рд╛рд▓реЗ рд╡рд░реНрдЧреЛрдВ рдХреЗ рд▓рд┐рдП, рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рд╡рд░реНрддрдорд╛рди
SynchronizationContext
TaskScheduler
рдФрд░ рд╡рд░реНрддрдорд╛рди
TaskScheduler
(рджреЛрдиреЛрдВ рдЬрд┐рдирдореЗрдВ рд╕реЗ рд╕реНрдерд┐рд░ рдкреНрд░рд╡рд╛рд╣ рддрдХ рдкрд╣реБрдВрдЪ рд╣реЛрддреА рд╣реИ) рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреА рдЕрддрд┐рд░рд┐рдХреНрдд рд▓рд╛рдЧрдд рдХрд╛рдлреА рдЕрдзрд┐рдХ рдмрдврд╝ рд╕рдХрддреА рд╣реИред рдпрджрд┐
await
рдХреЗ рдмрд╛рдж рдХреЗ рдХреЛрдб рдХреЛ рдореВрд▓ рд╕рдВрджрд░реНрдн рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ, рддреЛ
ConfigureAwait(false)
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдЗрди рд╕рднреА рдЦрд░реНрдЪреЛрдВ рд╕реЗ рдмрдЪрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕реЗ рдЕрдирд╛рд╡рд╢реНрдпрдХ рд░реВрдк рд╕реЗ рдкрдВрдХреНрддрд┐рдмрджреНрдз рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рд╕рднреА рдЙрдкрд▓рдмреНрдз рдЕрдиреБрдХреВрд▓рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рд╕реНрдЯреНрд░реАрдо рд╕реНрдЯреЗрдЯрд┐рдХреНрд╕ рддрдХ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдкрд╣реБрдВрдЪ рднреА рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред
рдЧрддрд┐рд░реЛрдз рдирд┐рд╡рд╛рд░рдг рдЙрд╕ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╡рд┐рдзрд┐ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ рдЬрд┐рд╕рдХрд╛
await
рдиреЗрдЯрд╡рд░реНрдХ рд╕реЗ рдХреБрдЫ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдиреЗ рдХреЗ
await
рдХрд░рддрд╛ рд╣реИред рдЖрдк рдЗрд╕ рд╡рд┐рдзрд┐ рдХреЛ рдХрд╣рддреЗ рд╣реИрдВ рдФрд░ рд╕рд┐рдВрдХреНрд░реЛрдирд╛рдЗрдЬрд╝реНрдб рдмреНрд▓реЙрдХ рдХрд░рддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЯрд╛рд╕реНрдХ рдХреЗ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВред рдЕрдм рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ рдХрд┐ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ рдпрджрд┐ рдХреЙрд▓ рддрдм рд╣реЛрддрд╛ рд╣реИ рдЬрдм рд╡рд░реНрддрдорд╛рди
SynchronizationContext
рдХреЙрдирдЯреЗрдХреНрд╕реНрдЯ рдЗрд╕рдореЗрдВ рдСрдкрд░реЗрд╢рди рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ 1 рддрдХ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ
MaxConcurrencySynchronizationContext
рдХреЙрдиреНрдЯреЗрдХреНрд╕реНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реАрдорд┐рдд рдХрд░рддрд╛ рд╣реИ, рдпрд╛ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рд░реВрдк рд╕реЗ, рдЕрдЧрд░ рдпрд╣ рдПрдХ рд╕рдВрджрд░реНрдн рдХреЗ рд▓рд┐рдП рдПрдХ рдПрдХрд▓ рдереНрд░реЗрдб рдХреЗ рд╕рд╛рде рдПрдХ рд╕рдВрджрд░реНрдн рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рдпреВрдЖрдИ рдереНрд░реЗрдб)ред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдЖрдк рдПрдХ рдПрдХрд▓ рдереНрд░реЗрдб рдореЗрдВ рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рдЗрд╕реЗ рдмреНрд▓реЙрдХ рдХрд░рддреЗ рд╣реИрдВ, рдСрдкрд░реЗрд╢рди рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВред рдбрд╛рдЙрдирд▓реЛрдб рдиреЗрдЯрд╡рд░реНрдХ рдкрд░ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХреЗ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХрд╛ рдЗрдВрддрдЬрд╛рд░ рдХрд░рддрд╛ рд╣реИред рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ,
Task
рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рд╕реЗ рд╡рд░реНрддрдорд╛рди
SynchronizationContext
(рдФрд░ рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ) рдкрд░ рдХрдмреНрдЬрд╛
Task
, рдФрд░ рдЬрдм рдиреЗрдЯрд╡рд░реНрдХ рд╕реЗ рдбрд╛рдЙрдирд▓реЛрдб рдкреВрд░рд╛ рд╣реЛ рдЬрд╛рдПрдЧрд╛, рддреЛ рдЗрд╕реЗ рд╡рд╛рдкрд╕
SynchronizationContext
рдХреЙрдиреНрдЯреЗрдХреНрд╕реНрдЯ рдХреЙрд▓рдмреИрдХ рдореЗрдВ рдХрддрд╛рд░рдмрджреНрдз рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЬреЛ рдмрд╛рдХреА рдСрдкрд░реЗрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░реЗрдЧрд╛ред рд▓реЗрдХрд┐рди рдПрдХрдорд╛рддреНрд░ рдзрд╛рдЧрд╛ рдЬреЛ рдХрддрд╛рд░ рдореЗрдВ рдХреЙрд▓рдмреИрдХ рдХреЛ рд╕рдВрднрд╛рд▓ рд╕рдХрддрд╛ рд╣реИ, рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдСрдкрд░реЗрд╢рди рдХреЗ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддреЗ рд╕рдордп рдЕрд╡рд░реБрджреНрдз рд╣реИред рдФрд░ рдпрд╣ рдСрдкрд░реЗрд╢рди рддрдм рддрдХ рдкреВрд░рд╛ рдирд╣реАрдВ рд╣реЛрдЧрд╛ рдЬрдм рддрдХ рдХрд┐ рдХреЙрд▓рдмреИрдХ рд╕рдВрд╕рд╛рдзрд┐рдд рди рд╣реЛ рдЬрд╛рдПред рдЧрддрд┐рд░реЛрдз! рдпрд╣ рддрдм рднреА рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдЬрдм рд╕рдВрджрд░реНрдн рд╕рдВрдЧрд╛рдорд┐рддрд┐ рдХреЛ 1 рддрдХ рд╕реАрдорд┐рдд рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рдВрд╕рд╛рдзрди рдХрд┐рд╕реА рддрд░рд╣ рд╕реЗ рд╕реАрдорд┐рдд рд╣реИрдВред рдЙрд╕реА рд╕реНрдерд┐рддрд┐ рдХреА рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ, рдХреЗрд╡рд▓
MaxConcurrencySynchronizationContext
рд▓рд┐рдП 4 рдХреЗ рдорд╛рди рдХреЗ рд╕рд╛рдеред рдСрдкрд░реЗрд╢рди рдХреЛ рдПрдХ рдмрд╛рд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп, рд╣рдо рд╕рдВрджрд░реНрдн рдХреЗ рд▓рд┐рдП 4 рдХреЙрд▓ рдХреА рдХрддрд╛рд░ рд▓рдЧрд╛рддреЗ рд╣реИрдВред рдкреНрд░рддреНрдпреЗрдХ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХреЗ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХреА рдкреНрд░рддреНрдпрд╛рд╢рд╛ рдореЗрдВ рддрд╛рд▓реЗред рд╕рднреА рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЛ рдЕрдм рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рддрд░реАрдХреЛрдВ рдХреЗ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХреЗ рдЗрдВрддрдЬрд╛рд░ рдореЗрдВ рдЕрд╡рд░реБрджреНрдз рдХрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдФрд░ рдХреЗрд╡рд▓ рдПрдХ рдЪреАрдЬ рдЬреЛ рдЙрдиреНрд╣реЗрдВ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧреА, рдпрджрд┐ рдЗрд╕ рд╕рдВрджрд░реНрдн рдореЗрдВ рдЙрдирдХреЗ рдХреЙрд▓рдмреИрдХ рд╕рдВрд╕рд╛рдзрд┐рдд рд╣реЛрддреЗ рд╣реИрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐, рд╡рд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХрдмреНрдЬрд╛ рдХрд░ рд▓рд┐рдпрд╛ рд╣реИред рдлрд┐рд░ рд╕реЗ рдЧрддрд┐рд░реЛрдзред рдпрджрд┐ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╡рд┐рдзрд┐
ConfigureAwait(false)
рдЙрдкрдпреЛрдЧ рдХрд░рддреА рд╣реИ, рддреЛ рдпрд╣ рдХреЙрд▓рдмреИрдХ рдХреЛ рдореВрд▓ рд╕рдВрджрд░реНрдн рдореЗрдВ рдкрдВрдХреНрддрд┐рдмрджреНрдз рдирд╣реАрдВ рдХрд░реЗрдЧрд╛, рдЬреЛ рдЧрддрд┐рд░реЛрдз рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╕реЗ рдмрдЪрдирд╛ рд╣реЛрдЧрд╛ред
рдХреНрдпрд╛ рдореБрдЭреЗ рдХреЙрдиреНрдлрд┐рдЧрд░рдПрд╡рд┐рдЯ (рд╕рддреНрдп) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ?
рдирд╣реАрдВ, рдЬрдм рддрдХ рдХрд┐ рдЖрдкрдХреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд╕рдВрдХреЗрдд рджреЗрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рди рд╣реЛ рдХрд┐ рдЖрдк
ConfigureAwait(false)
(рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╕реНрдереИрддрд┐рдХ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдЪреЗрддрд╛рд╡рдиреА рдЖрджрд┐ рдХреЛ рдЫрд┐рдкрд╛рдиреЗ рдХреЗ рд▓рд┐рдП
ConfigureAwait(false)
рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд░рд╣реЗ рд╣реИрдВред
ConfigureAwait(true)
рдорд╣рддреНрд╡рдкреВрд░реНрдг рдирд╣реАрдВ рд╣реИред рдпрджрд┐ рдЖрдк
await task
рдФрд░
await task
рддреБрд▓рдирд╛ рдХрд░рддреЗ рд╣реИрдВред
await task.ConfigureAwait(true)
, рддреЛ рд╡реЗ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рд░реВрдк рд╕реЗ рд╕рдорд╛рди рд╣реЛрдВрдЧреЗред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдпрджрд┐
ConfigureAwait(true)
рдХреЛрдб рдореЗрдВ рдореМрдЬреВрдж рд╣реИ, рддреЛ рдЗрд╕реЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рдирдХрд╛рд░рд╛рддреНрдордХ рдкрд░рд┐рдгрд╛рдо рдХреЗ рд╣рдЯрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
ConfigureAwait
рд╡рд┐рдзрд┐ рдПрдХ рдмреВрд▓рд┐рдпрди рдорд╛рди рд▓реЗрддреА рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдХреБрдЫ рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдореЗрдВ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЪрд░ рдХреЛ рдкрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛ рд╕рдХрддреА рд╣реИред рд▓реЗрдХрд┐рди 99% рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдорд╛рди рдЧрд▓рдд,
ConfigureAwait(false)
рд╕реЗрдЯ рд╣реИред
рдХрдиреНрдлрд┐рдЧрд░рд╡рд╛рдЗрдЯ (рдЧрд▓рдд) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрдм рдХрд░реЗрдВ?
рдпрд╣ рдЗрд╕ рдмрд╛рдд рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЖрдк рдПрдкреНрд▓рд┐рдХреЗрд╢рди-рд╕реНрддрд░реАрдп рдХреЛрдб рдпрд╛ рд╕рд╛рдорд╛рдиреНрдп-рдЙрджреНрджреЗрд╢реНрдп рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛрдб рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ рдпрд╛ рдирд╣реАрдВред
рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд▓рд┐рдЦрддреЗ рд╕рдордп, рдХреБрдЫ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдпрджрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЙрдбрд▓ / рд╡рд╛рддрд╛рд╡рд░рдг (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╡рд┐рдВрдбреЛрдЬ рдлреЙрд░реНрдо, рдбрдмреНрд▓реНрдпреВрдкреАрдПрдл, рдПрдПрд╕рдкреАред рдХреЛрд░) рдПрдХ рд╡рд┐рд╢реЗрд╖
SynchronizationContext
рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ, рддреЛ рдЗрд╕рдХреЗ рд▓рд┐рдП рд▓рдЧрднрдЧ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдПрдХ рдЕрдЪреНрдЫрд╛ рдХрд╛рд░рдг рд╣реИ: рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдХреЛрдб рдЖрдкрдХреЛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЙрдбрд▓ / рдкрд░реНрдпрд╛рд╡рд░рдг рдХреЗ рд╕рд╛рде рдЙрдЪрд┐рдд рдмрд╛рддрдЪреАрдд рдХреЗ рд▓рд┐рдП рд╕рд┐рдВрдХреНрд░реЛрдирд╛рдЗрдЬрд╝реЗрд╢рди рд╕рдВрджрд░реНрдн рдХрд╛ рдзреНрдпрд╛рди рд░рдЦрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдЖрдк Windows рдкреНрд░рдкрддреНрд░ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдореЗрдВ рдХреЛрдИ рдИрд╡реЗрдВрдЯ рд╣реИрдВрдбрд▓рд░ рд▓рд┐рдЦрддреЗ рд╣реИрдВ, xUnit рдореЗрдВ рдПрдХ рдкрд░реАрдХреНрд╖рдг, рдпрд╛ ASP.NET MVC рдирд┐рдпрдВрддреНрд░рдХ рдореЗрдВ рдХреЛрдб, рдЪрд╛рд╣реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЙрдбрд▓ рдиреЗ
SynchronizationContext
рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд┐рдпрд╛ рд╣реЛ, рддреЛ рдпрджрд┐ рдХреЛрдИ рдореМрдЬреВрдж рд╣реИ рддреЛ рдЖрдкрдХреЛ
SynchronizationContext
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рд╣реИ рдХрд┐ рдпрджрд┐
ConfigureAwait(true)
рдФрд░
await
, рддреЛ рдХреЙрд▓рдмреИрдХ / рдирд┐рд░рдВрддрд░рддрд╛ рдХреЛ рдореВрд▓ рд╕рдВрджрд░реНрдн рдореЗрдВ рд╡рд╛рдкрд╕ рднреЗрдЬ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ - рд╕рдм рдХреБрдЫ рд╡реИрд╕рд╛ рд╣реА рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рдЬреИрд╕рд╛ рдХрд┐ рдЗрд╕реЗ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдпрд╣рд╛рдВ рд╕реЗ рдЖрдк рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рдирд┐рдпрдо рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ:
рдпрджрд┐ рдЖрдк рдПрдкреНрд▓рд┐рдХреЗрд╢рди-рд╕реНрддрд░реАрдп рдХреЛрдб рд▓рд┐рдЦрддреЗ рд╣реИрдВ, рддреЛ ConfigureAwait(false)
рдЙрдкрдпреЛрдЧ рди рдХрд░реЗрдВ ред рдЖрдЗрдП рдХреНрд▓рд┐рдХ рд╣реИрдВрдбрд▓рд░ рдкрд░ рд╡рд╛рдкрд╕ рдЬрд╛рдПрдВ:
private static readonly HttpClient s_httpClient = new HttpClient(); private async void downloadBtn_Click(object sender, RoutedEventArgs e) { string text = await s_httpClient.GetStringAsync("http://example.com/currenttime"); downloadBtn.Content = text; }
downloadBtn.Content = text
рдореВрд▓ рд╕рдВрджрд░реНрдн рдореЗрдВ
downloadBtn.Content = text
рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдпрджрд┐ рдХреЛрдб рдиреЗ рдЗрд╕ рдирд┐рдпрдо рдХрд╛ рдЙрд▓реНрд▓рдВрдШрди рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХреЗ рдмрдЬрд╛рдп
ConfigureAwait (false)
рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИ, рддреЛ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдореВрд▓ рд╕рдВрджрд░реНрдн рдореЗрдВ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛:
private static readonly HttpClient s_httpClient = new HttpClient(); private async void downloadBtn_Click(object sender, RoutedEventArgs e) { string text = await s_httpClient.GetStringAsync("http://example.com/currenttime").ConfigureAwait(false);
рдЗрд╕рд╕реЗ рдЕрдиреБрдЪрд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реЛрдЧрд╛ред рд╡рд╣реА рдПрдХ рдХреНрд▓рд╛рд╕рд┐рдХ ASP.NET рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдореЗрдВ рдХреЛрдб рдкрд░ рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИ рдЬреЛ
HttpContext.Current
рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИред
ConfigureAwait(false)
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп,
Context.Current
рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛
ConfigureAwait(false)
рдмрд╛рдж рдХрд╛ рдкреНрд░рдпрд╛рд╕ рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рдЬрдиреНрдо рджреЗ рд╕рдХрддрд╛ рд╣реИред
рдпрд╣ рд╡рд╣реА рд╣реИ рдЬреЛ рд╕рд╛рдорд╛рдиреНрдп рдЙрджреНрджреЗрд╢реНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЛ рдЕрд▓рдЧ рдХрд░рддрд╛ рд╣реИред рд╡реЗ рднрд╛рдЧ рдореЗрдВ рд╕рд╛рд░реНрд╡рднреМрдорд┐рдХ рд╣реИрдВ рдХреНрдпреЛрдВрдХрд┐ рд╡реЗ рдЙрд╕ рдкрд░реНрдпрд╛рд╡рд░рдг рдХреА рдкрд░рд╡рд╛рд╣ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рд╕рдореЗрдВ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЖрдк рдЙрдиреНрд╣реЗрдВ рд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╕реЗ, рдХреНрд▓рд╛рдЗрдВрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╕реЗ рдпрд╛ рдкрд░реАрдХреНрд╖рдг рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ - рдЗрд╕рд╕реЗ рдХреЛрдИ рдлрд░реНрдХ рдирд╣реАрдВ рдкрдбрд╝рддрд╛, рдХреНрдпреЛрдВрдХрд┐ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛрдб рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЙрдбрд▓ рдХреЗ рд▓рд┐рдП рдЕрдЬреНрдЮреЗрдп рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЕрдЬреНрдЮреЗрдп рдХрд╛ рдпрд╣ рднреА рдЕрд░реНрде рд╣реИ рдХрд┐ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдореЙрдбрд▓ рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рднреА рдирд╣реАрдВ рдХрд░реЗрдЧрд╛, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдирд┐рдпрдВрддреНрд░рдг рддрдХ рдкрд╣реБрдВрдЪ рдкреНрд░рд╛рдкреНрдд рдирд╣реАрдВ рдХрд░реЗрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рд╕рд╛рдорд╛рдиреНрдп рдкреНрд░рдпреЛрдЬрди рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЙрдирдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рдЬрд╛рдирддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ рдХреЛрдб рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреА рдХреЛрдИ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рд╣рдо рдореВрд▓ рд╕рдВрджрд░реНрдн рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдирд┐рд░рдВрддрд░рддрд╛ / рдХреЙрд▓рдмреИрдХ рд╕реЗ рдмрдЪ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рд╣рдо
ConfigureAwait(false)
рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдРрд╕рд╛ рдХрд░рддреЗ рд╣реИрдВ, рдЬреЛ рд╣рдореЗрдВ рдкреНрд░рджрд░реНрд╢рди рд▓рд╛рдн рджреЗрддрд╛ рд╣реИ рдФрд░ рд╡рд┐рд╢реНрд╡рд╕рдиреАрдпрддрд╛ рдмрдврд╝рд╛рддрд╛ рд╣реИред рдпрд╣ рд╣рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреА рдУрд░ рд▓реЗ рдЬрд╛рддрд╛ рд╣реИ:
рдпрджрд┐ рдЖрдк рд╕рд╛рдорд╛рдиреНрдп-рдЙрджреНрджреЗрд╢реНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЛрдб рд▓рд┐рдЦ рд░рд╣реЗ рд╣реИрдВ, рддреЛ ConfigureAwait(false)
рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ ред рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ .NET рдХреЛрд░ рд░рдирдЯрд╛рдЗрдо рд▓рд╛рдЗрдмреНрд░реЗрд░реАрдЬрд╝ рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ (рдпрд╛ рд▓рдЧрднрдЧ рд╣рд░) рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИ, ConfigureAwait (рдЧрд▓рдд) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ; рдХреБрдЫ рдЕрдкрд╡рд╛рджреЛрдВ рдХреЗ рд╕рд╛рде, рдЬреЛ рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд╕рдВрднрд╛рд╡рдирд╛ рдХреАрдбрд╝реЗ рд╣реИрдВ, рдЙрдиреНрд╣реЗрдВ рдареАрдХ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред ,
PR ConfigureAwait(false)
HttpClient
.
. , (, , , ) , API, . , , тАЭ " . , , Where LINQ:
public static async IAsyncEnumerable<T> WhereAsync(this IAsyncEnumerable<T> source, Func<T, bool> predicate)
.
predicate
SynchronizationContext
?
WhereAsync
, ,
ConfigureAwait(false)
.
:
ConfigureAwait(false)
/app-model-agnostic .
ConfigureAwait (false), ?
, , . ,
await
. , , . , , , ,
ConfigureAwait(false)
, , .
ConfigureAwait (false) , тАФ ?
, . FAQ.
await task.ConfigureAwait(false)
, ( ),
ConfigureAwait(false)
, - , .
,
await
, ,
SynchronizationContext
TaskScheduler
. ,
CryptoStream
.NET , .
awaiter
рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдкрд╣рд▓реЗ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХреЗ рдмрд╛рдж рдХреЛрдб рдереНрд░реЗрдб рдкреВрд▓ рдереНрд░реЗрдб рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рднреА, рдЖрдк рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ рдЕрдЧрд▓рд╛ рдЗрдВрддрдЬрд╛рд░ рдЕрднреА рднреА рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реИ ConfigureAwait(false)
; рддрдХрдиреАрдХреА рд░реВрдк рд╕реЗ, рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдХреЛрдб рд╕рдореАрдХреНрд╖рд╛ рдХреЛ рдмрд╣реБрдд рд╕рд░рд▓ рдХрд░рддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╕рдордЭрдиреЗ рдХреА рдХреЛрдИ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ ConfigureAwait(false)
редрдХреНрдпрд╛ ConfigureAwait (рдЧрд▓рдд) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП Task.Run рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ?
рд╣рд╛рдВ, рдпрджрд┐ рдЖрдк рд▓рд┐рдЦрддреЗ рд╣реИрдВ: Task.Run(async delegate { await SomethingAsync();
ConfigureAwait(false)
SomethingAsync()
, ,
Task.Run
, ,
SynchronizationContext.Current
null
. ,
Task.Run
TaskScheduler.Default
,
TaskScheduler.Current
Default
. ,
await
,
ConfigureAwait(false)
. , . :
Task.Run(async delegate { SynchronizationContext.SetSynchronizationContext(new SomeCoolSyncCtx()); await SomethingAsync();
рддрдм рдХреЛрдб рдЕрдВрджрд░ SomethingAsync
рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ SynchronizationContext.Current
рдЙрджрд╛рд╣рд░рдг рджреЗрдЦреЗрдЧрд╛ SomeCoolSyncCtx
ред рдФрд░ рдпрд╣ await
, рдФрд░ SomeAsync рдХреЗ рдЕрдВрджрд░ рдХреЛрдИ рднреА рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХреА рдЧрдИ рдЕрдкреЗрдХреНрд╖рд╛рдПрдБ рдЗрд╕ рд╕рдВрджрд░реНрдн рдореЗрдВ рд╡рд╛рдкрд╕ рдирд╣реАрдВ рдХреА рдЬрд╛рдПрдВрдЧреАред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдпрд╣ рд╕рдордЭрдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рдХрддрд╛рд░ рдореЗрдВ рд░рдЦреЗ рдЧрдП рд╕рднреА рдХреЛрдб рдХреНрдпрд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрд╛ рдХреНрдпрд╛ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдХреНрдпрд╛ рдЗрд╕рдХреЗ рдХрд╛рд░реНрдп рдПрдХ рдмрд╛рдзрд╛ рдмрди рд╕рдХрддреЗ рд╣реИрдВредрдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдЕрддрд┐рд░рд┐рдХреНрдд рдХрд╛рд░реНрдп рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдиреЗ / рдХрддрд╛рд░ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдХрд╛рд░рдг рднреА рд╣реЛрддрд╛ рд╣реИред рдкреНрд░рджрд░реНрд╢рди рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдпрд╣ рдПрдкреНрд▓рд┐рдХреЗрд╢рди / рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рд▓рд┐рдП рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред, , , . , ,
ConfigureAwait(false)
CA2007 . ,
ConfigureAwait
, , . , , - , ,
ConfigureAwait(false)
.
SynchronizationContext.SetSynchronizationContext, ConfigureAwait (false)?
рдирд╣реАрдВред , .
:
Task t; SynchronizationContext old = SynchronizationContext.Current; SynchronizationContext.SetSynchronizationContext(null); try { t = CallCodeThatUsesAwaitAsync();
,
CallCodeThatUsesAwaitAsync
null
. . ,
await
TaskScheduler.Current
.
TaskScheduler
,
await
'
CallCodeThatUsesAwaitAsync
TaskScheduler
.
Task.Run
FAQ, : ,
try
, ( ).
:
SynchronizationContext old = SynchronizationContext.Current; SynchronizationContext.SetSynchronizationContext(null); try { await t; } finally { SynchronizationContext.SetSynchronizationContext(old); }
рджреЗрдЦрд┐рдП рдХреНрдпрд╛ рд╕рдорд╕реНрдпрд╛ рд╣реИ? рдиреЛрдЯрд┐рд╕ рдХрд░рдирд╛ рдереЛрдбрд╝рд╛ рдХрдард┐рди рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдкреНрд░рднрд╛рд╡рд╢рд╛рд▓реА рд╣реИред рдЗрд╕ рдмрд╛рдд рдХреА рдХреЛрдИ рдЧрд╛рд░рдВрдЯреА рдирд╣реАрдВ рд╣реИ рдХрд┐ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рд╕реЗ рдореВрд▓ рдХреЙрд▓ рдореЗрдВ рдПрдХ рдХреЙрд▓рдмреИрдХ / рдЬрд╛рд░реА рд░рд╣реЗрдЧрд╛ред рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рд╣реИ рдХрд┐ SynchronizationContext
рдореВрд▓ рдореЗрдВ рд╡рд╛рдкрд╕реА рдореВрд▓ рдзрд╛рдЧреЗ рдореЗрдВ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреА рд╣реИ, рдЬреЛ рдЗрд╕ рддрдереНрдп рдХреЛ рдЬрдиреНрдо рджреЗ рд╕рдХрддреА рд╣реИ рдХрд┐ рдмрд╛рдж рдореЗрдВ рдЗрд╕ рдзрд╛рдЧреЗ рдореЗрдВ рдХрд╛рдо рдХреА рд╡рд╕реНрддреБрдУрдВ рдХреЛ рдЧрд▓рдд рд╕рдВрджрд░реНрдн рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛ред рдЗрд╕рдХрд╛ рдкреНрд░рддрд┐рдХрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рд╡рд┐рд╢реЗрд╖ рд╕рдВрджрд░реНрдн рд╕реЗрдЯ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд▓рд┐рдЦрд┐рдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЙрдбрд▓ рдЖрдорддреМрд░ рдкрд░ рдХрд┐рд╕реА рднреА рдЕрддрд┐рд░рд┐рдХреНрдд рдХрд╕реНрдЯрдо рдХреЛрдб рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рд░реАрд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдб рдЬреЛрдбрд╝рддреЗ рд╣реИрдВред рдФрд░ рдЕрдЧрд░ рдпрд╣ рдПрдХ рдзрд╛рдЧреЗ рдореЗрдВ рд╣реЛрддрд╛ рд╣реИ, рддреЛ рднреА рдХреБрдЫ рд╕рдордп рд▓рдЧ рд╕рдХрддрд╛ рд╣реИ рдЬрд┐рд╕рдХреЗ рджреМрд░рд╛рди рд╕рдВрджрд░реНрдн рдареАрдХ рд╕реЗ рдмрд╣рд╛рд▓ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдФрд░ рдЕрдЧрд░ рдпрд╣ рдПрдХ рдЕрд▓рдЧ рдзрд╛рдЧреЗ рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдЧрд▓рдд рд╕рдВрджрд░реНрдн рдХреА рд╕реНрдерд╛рдкрдирд╛ рдХреЛ рдЬрдиреНрдо рджреЗ рд╕рдХрддрд╛ рд╣реИред рдФрд░ рдЗрд╕реА рддрд░рд╣ред
рдЖрджрд░реНрд╢ рд╕реЗ рдмрд╣реБрдд рджреВрд░редрдпрджрд┐ рдореБрдЭреЗ GetAwaiter () .GetResult () рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реИ рддреЛ рдХреНрдпрд╛ рдореБрдЭреЗ рдХреЙрдиреНрдлрд┐рдЧрд░рдПрд╡рд┐рдЯ (рдЧрд▓рдд) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ?
рдирд╣реАрдВред
ConfigureAwait
рдХреЗрд╡рд▓ рдХреЙрд▓рдмреИрдХ рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рддрд╛ рд╣реИред рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЗ рд▓рд┐рдП awaiter
рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ рдЖрдк awaiter
рд╕рдВрдкрддреНрддрд┐ IsCompleted
, рд╡рд┐рдзрд┐рдпрд╛рдБ GetResult
рдФрд░ OnCompleted
рд╡реИрдХрд▓реНрдкрд┐рдХ рд░реВрдк рд╕реЗ (рдЕрд╕реБрд░рдХреНрд╖рд┐рдд рдХреИрдлреЗ рд╡рд┐рдзрд┐ рдХреЗ рд╕рд╛рде) рдкреНрд░рджрд╛рди рдХрд░реЗрдВред ConfigureAwait
рдХреЗрд╡рд▓ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рддрд╛ рд╣реИ {Unsafe}OnCompleted
, рдЗрд╕рд▓рд┐рдП рдпрджрд┐ рдЖрдк рд╕реАрдзреЗ рдХреЙрд▓ рдХрд░рддреЗ рд╣реИрдВ GetResult()
, рднрд▓реЗ рд╣реА рдЖрдк рдЗрд╕рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрд░рддреЗ рд╣реИрдВ TaskAwaiter
рдпрд╛ ConfiguredTaskAwaitable.ConfiguredTaskAwaiter
рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ рдХреЛрдИ рдЕрдВрддрд░ рдирд╣реАрдВ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдпрджрд┐ рдЖрдк рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ task.ConfigureAwait(false).GetAwaiter().GetResult()
рдЖрдк рдЗрд╕реЗ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ task.GetAwaiter().GetResult()
(рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╕реЛрдЪреЗрдВ рдХрд┐ рдХреНрдпрд╛ рдЖрдкрдХреЛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЗрд╕ рддрд░рд╣ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ)редрдореБрдЭреЗ рдкрддрд╛ рд╣реИ рдХрд┐ рдХреЛрдб рдПрдХ рдРрд╕реЗ рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ рдЪрд▓рддрд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдХрднреА рднреА рдПрдХ рд╡рд┐рд╢реЗрд╖ рд╕рд┐рдВрдХреНрд░реЛрдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреЙрдирдЯреЗрдХреНрд╕реНрдЯ рдпрд╛ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдЯрд╛рд╕реНрдХрд╕реНрдХрд┐рдбрд░ рдирд╣реАрдВ рд╣реЛрдЧрд╛ред рдХреНрдпрд╛ рдореИрдВ рдХреЙрдиреНрдлрд┐рдЧрд░рдПрд╡рд┐рдЯ (рдЧрд▓рдд) рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ?
рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ред , ┬л┬╗. , , , ,
SynchronizationContext
TaskScheduler
, , . , , .
, .NET Core ConfigureAwait (false). ?
рдРрд╕реЗ рдирд╣реАрдВред
.NET рдХреЛрд░ рдореЗрдВ рдХрд╛рдо рдХрд░рдирд╛ рдЙрд╕реА рддрд░рд╣ рд╕реЗ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдЬреИрд╕реЗ .NET рдлреНрд░реЗрдорд╡рд░реНрдХ рдореЗрдВ рдХрд╛рдо рдХрд░рддреЗ рд╕рдордпред рдЗрд╕ рд╕рдВрдмрдВрдз рдореЗрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рдмрджрд▓рд╛ рд╣реИредрдпрд╣ рдмрджрд▓ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдХреБрдЫ рд╡рд╛рддрд╛рд╡рд░рдг рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд░рддреЗ рд╣реИрдВ SynchronizationContext
ред рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рдЬрдмрдХрд┐ .NET рдлреНрд░реЗрдорд╡рд░реНрдХ рдореЗрдВ рдХреНрд▓рд╛рд╕рд┐рдХ ASP.NET рдХрд╛ рдЕрдкрдирд╛ рд╣реИ SynchronizationContext
, ASP.NET рдХреЛрд░ рдирд╣реАрдВ рд╣реИред рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рд╣реИ рдХрд┐ ASP.NET рдХреЛрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдЪрд▓ рд░рд╣реЗ рдХреЛрдб рдХреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рд╡рд┐рд╢реЗрд╖ рдХреЛрдб рдирд╣реАрдВ рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛ SynchronizationContext
, рдЬреЛ ConfigureAwait(false)
рдЗрд╕ рд╡рд╛рддрд╛рд╡рд░рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЛ рдХрдо рдХрд░рддрд╛ рд╣реИредрд╣рд╛рд▓рд╛рдВрдХрд┐, рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдХреЛрдИ рдкреНрд░рдерд╛ SynchronizationContext
рдпрд╛ рдХрднреА рдирд╣реАрдВ рд╣реЛрдЧреАTaskScheduler
. - ( , ) , ,
await
' ASP.NET Core ,
ConfigureAwait(false)
. , , ( -) ,
ConfigureAwait(false)
.
ConfigureAwait, ┬л foreach┬╗ IAsyncEnumerable?
рд╣рд╛рдВред .
MSDN .
Await foreach
, ,
IAsyncEnumerable<T>
. , API. .NET
ConfigureAwait
IAsyncEnumerable<T>
, ,
IAsyncEnumerable<T>
Boolean
.
MoveNextAsync
DisposeAsync
. , , .
ConfigureAwait, 'await using' IAsyncDisposable?
, .
IAsyncEnumerable<T>
, .NET
ConfigureAwait
IAsyncDisposable
await using
, , ( ,
DisposeAsync
):
await using (var c = new MyAsyncDisposableClass().ConfigureAwait(false)) { ... }
,
c
тАФ
MyAsyncDisposableClass
,
System.Runtime.CompilerServices.ConfiguredAsyncDisposable
,
ConfigureAwait
IAsyncDisposable
.
, :
var c = new MyAsyncDisposableClass(); await using (c.ConfigureAwait(false)) { ... }
c
MyAsyncDisposableClass
.
c
; , .
рдореИрдВрдиреЗ рдХрдиреНрдлрд┐рдЧрд░рд╡рд╛рдЗрдЯ (рдЭреВрдард╛) рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛, рд▓реЗрдХрд┐рди рдореЗрд░рд╛ рдПрд╕рд┐рдВрдХреНрд▓реЛрдХреНрдХрд▓ рдЗрдВрддрдЬрд╛рд░ рдХреЗ рдмрд╛рдж рднреА рдХреЛрдб рдореЗрдВ рдмрд╣рддрд╛ рд░рд╣рд╛ред рдХреНрдпрд╛ рдпрд╣ рдПрдХ рдмрдЧ рд╣реИ?
рдирд╣реАрдВ, рдпрд╣ рдХрд╛рдлреА рдЕрдкреЗрдХреНрд╖рд┐рдд рд╣реИред рдбреЗрдЯрд╛ рдкреНрд░рд╡рд╛рд╣ AsyncLocal<T>
рд╡рд╣ рд╣рд┐рд╕реНрд╕рд╛ ExecutionContext
рд╣реИ рдЬреЛ рдЗрд╕рд╕реЗ рдЕрд▓рдЧ рд╣реЛрддрд╛ рд╣реИ SynchronizationContext
ред рдЬрдм рддрдХ рдЖрдк рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ ExecutionContext
рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╡рд╛рд▓реА рдзрд╛рд░рд╛ рдХреЛ рдЕрдХреНрд╖рдо рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ ExecutionContext.SuppressFlow()
, ExecutionContext
(рдФрд░ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдбреЗрдЯрд╛ AsyncLocal <T>
) рд╣рдореЗрд╢рд╛ рдЧреБрдЬрд░рддрд╛ рд░рд╣реЗрдЧрд╛ awaits
, рдЪрд╛рд╣реЗ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ ConfigureAwait
рдореВрд▓ рдкрд░ рдХрдмреНрдЬрд╛ рдХрд░рдиреЗ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рдП SynchronizationContext
ред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдЕрдзрд┐рдХ рд╡рд┐рд╡рд░рдг рдкрд░ рдЪрд░реНрдЪрд╛ рдХреА рдЧрдИ рд╣реИ редрдХреНрдпрд╛ рднрд╛рд╖рд╛ рдЙрдкрдХрд░рдг рдореЗрд░реА рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдореЗрдВ рдХреЙрдиреНрдлрд┐рдЧрд░рдПрд╡рд┐рдЯ (рдЧрд▓рдд) рдХрд╛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╕реЗ рдмрдЪрдиреЗ рдореЗрдВ рдореЗрд░реА рдорджрдж рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ?
рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдбреЗрд╡рд▓рдкрд░ рдХрднреА-рдХрднреА ConfigureAwait(false)
рдХрдо рдЖрдХреНрд░рд╛рдордХ рд╡рд┐рдХрд▓реНрдк рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдФрд░ рдкреВрдЫрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╢рд┐рдХрд╛рдпрдд рдХрд░рддреЗ рд╣реИрдВ редрд╡рд░реНрддрдорд╛рди рдореЗрдВ рд╡реЗ рдирд╣реАрдВ рд╣реИрдВ, рдХрдо рд╕реЗ рдХрдо рд╡реЗ рднрд╛рд╖рд╛ / рд╕рдВрдХрд▓рдХ / рд░рдирдЯрд╛рдЗрдо рдореЗрдВ рдирд╣реАрдВ рдмрдиреЗ рд╣реИрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдХрдИ рд╕реБрдЭрд╛рд╡ рд╣реИрдВ рдХрд┐ рдЗрд╕реЗ рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП: 1 , 2 , 3 , 4 редрдпрджрд┐ рдЖрдк рдЬрд┐рд╕ рд╡рд┐рд╖рдп рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ, рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдирдП рдФрд░ рджрд┐рд▓рдЪрд╕реНрдк рд╡рд┐рдЪрд╛рд░ рд╣реИрдВ, рддреЛ рдореВрд▓ рд▓реЗрдЦ рдХреЗ рд▓реЗрдЦрдХ рдЖрдкрдХреЛ рдЪрд░реНрдЪрд╛ рдХреЗ рд▓рд┐рдП рдЖрдордВрддреНрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВред