Task
and other structures to manage asynchronous operations adds some overhead. If your operation is really long, for example, performing an IO request, then these expenses will not be noticeable in general. And if your operation is short or takes several processor cycles, then it may be better to perform this operation synchronously.Async
and returns a task, then most likely you should use it asynchronously.async/await
makes the process of creating code and reading it much easier than using Task
tasks. public Task<Data> GetDataAsync() { return MyWebService.FetchDataAsync() .ContinueWith(t => new Data (t.Result)); }
public async Task<Data> GetDataAsync() { var result = await MyWebService.FetchDataAsync(); return new Data (result); }
Task
builds a chain of continuations that increases in accordance with the number of tasks connected in series, and the state of the system is controlled through the closures found by the compiler.Async/await
builds a state machine that does not use additional resources when adding new steps. However, the compiler can define more variables for storing state machine stacks, depending on your code (and compiler). The article on MSDN describes the details of what is happening.async/await
will use less resources and run faster than task tasks.await
will cause a NullReferenceException
if it receives null
instead of a task, and handling this will make your code less readable. public async Task<Data> GetDataAsync(bool getLatestData) { Task<WebData> task = null; if (getLatestData) task = MyWebService.FetchDataAsync(); // // null WebData result = null; if (task != null) result = await task; return new Data (result); }
public async Task<Data> GetDataAsync(bool getLatestData) { var task = getLatestData ? MyWebService.FetchDataAsync() : Empty<WebData>.Task; // // task null return new Data (await task); }
public static class Empty<T> { public static Task<T> Task { get { return _task; } } private static readonly Task<T> _task = System.Threading.Tasks.Task.FromResult(default(T)); }
public Task<byte[]> GetContentsOfUrl(string url) { byte[] bytes; if (_cache.TryGetValue(url, out bytes)) // return Task<byte[]>.Factory.StartNew(() => bytes); bytes = MyWebService.GetContentsAsync(url) .ContinueWith(t => { _cache.Add(url, t.Result); return t.Result; ); } // ( ) private static Dictionary<string, byte[]> _cache = new Dictionary<string, byte[]>();
public Task<byte[]> GetContentsOfUrl(string url) { Task<byte[]> bytes; if (!_cache.TryGetValue(url, out bytes)) { bytes = MyWebService.GetContentsAsync(url); _cache.Add(url, bytes); } return bytes; } // ( ) private static Dictionary<string, Task<byte[]>> _cache = new Dictionary<string, Task<byte[]>>();
async/await
, the compiler creates a state machine that stores variables and a stack. For example: public static async Task FooAsync() { var data = await MyWebService.GetDataAsync(); var otherData = await MyWebService.GetOtherDataAsync(); Console.WriteLine("{0} = "1", data, otherdata); }
[StructLayout(LayoutKind.Sequential), CompilerGenerated] private struct <FooAsync>d__0 : <>t__IStateMachine { private int <>1__state; public AsyncTaskMethodBuilder <>t__builder; public Action <>t__MoveNextDelegate; public Data <data>5__1; public OtherData <otherData>5__2; private object <>t__stack; private object <>t__awaiter; public void MoveNext(); [DebuggerHidden] public void <>t__SetMoveNextDelegate(Action param0); }
Async
value of the call with await
, the variable will fall into the internal stack: public static async Task FooAsync() { var data = MyWebService.GetDataAsync(); var otherData = MyWebService.GetOtherDataAsync(); // // await- Console.WriteLine("{0} = "1", await data, await otherdata); }
async/await
is not the same as Task.ContinueWith/Wait
. In general, you can replace the implementation from Task
with await
, but there may be some performance and stability issues. Let's take a closer look.await
code will continue to work in the context in which it was launched. This is convenient because basically you want the security context to be restored, and you want your code after await to have access to the Windows UI objects, if it already had access to them at startup. Note that Task.Factory.StartNew
does not restore context. public ActionResult ActionAsync() { // DEADLOCK: // , var data = GetDataAsync().Result; return View(data); } private async Task<string> GetDataAsync() { // var result = await MyWebService.GetDataAsync(); return result.ToString(); }
Wait
to wait for the task to finish right here.Wait
. (c await
is somewhat better.)Wait
for tasks in single-threaded synchronization contexts, such as:Task
in certain cases, and the framework itself will wait for the task to be completed. Trust him this process: public async Task<ActionResult> ActionAsync() { // async/await Task var data = await GetDataAsync(); return View(data); }
async/await
much of the complexity is now handled by the compiler. And your code gets more reliability, and now you are less likely to be forced to contend with the nuances of ThreadPool
.ConfigureAwait
if you are creating a library.ConfigureAwait
to tell the system that it should not perform a background task in your context. The disadvantage of this is that the background task will not have access to the same synchronization context, so you will lose access to the Windows UI or HttpContext
(although you will still have your security context).Task
, you most likely do not know how it will be called. So it may be safer to add ConfigureAwait(false)
to your task before returning it. private async Task<string> GetDataAsync() { // ConfigureAwait(false) , // var result = await MyWebService.GetDataAsync().ConfigureAwait(false); return result.ToString(); }
public async Task<Data> GetContentsOfUrl(string url) { // , // if (url == null) throw new ArgumentNullException(); var data = await MyWebService.GetContentsOfUrl(); return data.DoStuffToIt(); }
Task
delegate will also be sent to the code waiting for the task (awaiter). public Task<Data> GetContentsOfUrl(string url) { return Task<Data>.Factory.StartNew(() => { // , // if (url == null) throw new ArgumentNullException(); var data = await MyWebService.GetContentsOfUrl(); return data.DoStuffToIt(); } }
public Task<Data> GetContentsOfUrl(string url) { // if (url == null) throw new ArgumentNullException(); return Task<Data>.Factory.StartNew(() => { var data = await MyWebService.GetContentsOfUrl(); return data.DoStuffToIt(); } }
async/await
instead of creating task chains through Task
.Source: https://habr.com/ru/post/162353/
All Articles