
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