{"id":2371,"date":"2014-03-05T13:00:29","date_gmt":"2014-03-05T13:00:29","guid":{"rendered":"http:\/\/writeasync.net\/?p=2371"},"modified":"2014-03-05T05:26:37","modified_gmt":"2014-03-05T05:26:37","slug":"hidden-costs-of-async","status":"publish","type":"post","link":"http:\/\/writeasync.net\/?p=2371","title":{"rendered":"Hidden costs of &#8216;async&#8217;"},"content":{"rendered":"<p>In a <a href=\"http:\/\/writeasync.net\/?p=101\" title=\"Async coding guidelines\">very early post<\/a>, I stated:<\/p>\n<blockquote><p>An &#8216;async&#8217; method is not free. The compiler does some complex code generation steps to morph your method into a proper asynchronous state machine with all the associated exception handling logic, management of continuation callbacks, etc.<\/p><\/blockquote>\n<p>Let&#8217;s explore this in a bit more detail. First, we will start with a very basic console application:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nnamespace ConsoleApplication1\r\n{\r\n    using System;\r\n    using System.Threading.Tasks;\r\n\r\n    internal sealed class Program\r\n    {\r\n        private static void Main(string&#x5B;] args)\r\n        {\r\n            WaitOneSecondAwaitAsync().Wait();\r\n            WaitOneSecondPassThroughAsync().Wait();\r\n        }\r\n\r\n        private static Task WaitOneSecondPassThroughAsync()\r\n        {\r\n            return Task.Delay(TimeSpan.FromSeconds(1.0d));\r\n        }\r\n\r\n        private static async Task WaitOneSecondAwaitAsync()\r\n        {\r\n            await Task.Delay(TimeSpan.FromSeconds(1.0d));\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>Now let&#8217;s use <a href=\"http:\/\/ilspy.net\/\">ILSpy<\/a> to decompile the app so we can see all the generated code. To do this, make sure to uncheck &#8220;Decompile async methods (async\/await)&#8221; in the Decompiler tab under View -&gt; Options. The first thing to note is how much additional code the single line <code>await<\/code> call actually expands to in the <code>WaitOneSecondAwaitAsync<\/code> method:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n&#x5B;DebuggerStepThrough, AsyncStateMachine(typeof(Program.&lt;WaitOneSecondAwaitAsync&gt;d__0))]\r\nprivate static Task WaitOneSecondAwaitAsync()\r\n{\r\n\tProgram.&lt;WaitOneSecondAwaitAsync&gt;d__0 &lt;WaitOneSecondAwaitAsync&gt;d__;\r\n\t&lt;WaitOneSecondAwaitAsync&gt;d__.&lt;&gt;t__builder = AsyncTaskMethodBuilder.Create();\r\n\t&lt;WaitOneSecondAwaitAsync&gt;d__.&lt;&gt;1__state = -1;\r\n\tAsyncTaskMethodBuilder &lt;&gt;t__builder = &lt;WaitOneSecondAwaitAsync&gt;d__.&lt;&gt;t__builder;\r\n\t&lt;&gt;t__builder.Start&lt;Program.&lt;WaitOneSecondAwaitAsync&gt;d__0&gt;(ref &lt;WaitOneSecondAwaitAsync&gt;d__);\r\n\treturn &lt;WaitOneSecondAwaitAsync&gt;d__.&lt;&gt;t__builder.Task;\r\n}\r\n<\/pre>\n<p>Now locate the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/saxz13w4.aspx\"><code>struct<\/code><\/a> inside <code>Program<\/code> named <code>&lt;WaitOneSecondAwaitAsync&gt;d__0<\/code> and look at its definition:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing ConsoleApplication1;\r\nusing System;\r\nusing System.Diagnostics;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\nusing System.Threading.Tasks;\r\n\r\n&#x5B;CompilerGenerated]\r\n&#x5B;StructLayout(LayoutKind.Auto)]\r\nprivate struct &lt;WaitOneSecondAwaitAsync&gt;d__0 : IAsyncStateMachine\r\n{\r\n    public int &lt;&gt;1__state;\r\n    public AsyncTaskMethodBuilder &lt;&gt;t__builder;\r\n    private TaskAwaiter &lt;&gt;u__$awaiter1;\r\n    private object &lt;&gt;t__stack;\r\n\r\n    void IAsyncStateMachine.MoveNext()\r\n    {\r\n        try\r\n        {\r\n            int num = this.&lt;&gt;1__state;\r\n            TaskAwaiter taskAwaiter;\r\n            if (num != 0)\r\n            {\r\n                taskAwaiter = Task.Delay(TimeSpan.FromSeconds(1.0)).GetAwaiter();\r\n                if (!taskAwaiter.IsCompleted)\r\n                {\r\n                    this.&lt;&gt;1__state = 0;\r\n                    this.&lt;&gt;u__$awaiter1 = taskAwaiter;\r\n                    this.&lt;&gt;t__builder.AwaitUnsafeOnCompleted&lt;TaskAwaiter, Program.&lt;WaitOneSecondAwaitAsync&gt;d__0&gt;(ref taskAwaiter, ref this);\r\n                    return;\r\n                }\r\n            }\r\n            else\r\n            {\r\n                taskAwaiter = this.&lt;&gt;u__$awaiter1;\r\n                this.&lt;&gt;u__$awaiter1 = default(TaskAwaiter);\r\n                this.&lt;&gt;1__state = -1;\r\n            }\r\n\r\n            taskAwaiter.GetResult();\r\n            taskAwaiter = default(TaskAwaiter);\r\n        }\r\n        catch (Exception exception)\r\n        {\r\n            this.&lt;&gt;1__state = -2;\r\n            this.&lt;&gt;t__builder.SetException(exception);\r\n            return;\r\n        }\r\n        this.&lt;&gt;1__state = -2;\r\n        this.&lt;&gt;t__builder.SetResult();\r\n    }\r\n\r\n    &#x5B;DebuggerHidden]\r\n    void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine param0)\r\n    {\r\n        this.&lt;&gt;t__builder.SetStateMachine(param0);\r\n    }\r\n}\r\n<\/pre>\n<p>All this just to <code>await<\/code> one <code>Task<\/code>! Hopefully it is clearer now why <strong>you should simply pass through when it is convenient to do so<\/strong>.<\/p>\n<p>One more thing about <code>async<\/code> methods that may be surprising in some circumstances: they will <em>never<\/em> throw synchronously. Consider this code:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate static async Task AppendLineAsync(string path, string line)\r\n{\r\n    if (path == null)\r\n    {\r\n        throw new ArgumentNullException(&quot;path&quot;);\r\n    }\r\n\r\n    using (FileStream stream = GetAsyncStream(path))\r\n    {\r\n        stream.Seek(0, SeekOrigin.End);\r\n        byte&#x5B;] buffer = Encoding.UTF8.GetBytes(line + Environment.NewLine);\r\n        await stream.WriteAsync(buffer, 0, buffer.Length);\r\n    }\r\n}\r\n<\/pre>\n<p>If you call this method with a null <code>path<\/code> you will get this exception but <em>only<\/em> after <code>await<\/code>ing:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nSystem.AggregateException: One or more errors occurred. ---&gt; System.ArgumentNullException: Value cannot be null.\r\nParameter name: path\r\n   at ConsoleApplication1.Program.&lt;AppendLineAsync&gt;d__0.MoveNext()\r\n&#x5B; . . . ]\r\n<\/pre>\n<p>If you prefer &#8220;throw on start&#8221; behavior, you need to do all the validation <em>upfront<\/em> in a non-<code>async<\/code> method and then pass through to an inner <code>async<\/code> method where all the actual logic lives. The pattern looks something like this:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate static Task AppendLineAsync(string path, string line)\r\n{\r\n    if (path == null)\r\n    {\r\n        throw new ArgumentNullException(&quot;path&quot;);\r\n    }\r\n\r\n    return AppendLineInnerAsync(path, line);\r\n}\r\n\r\nprivate static async Task AppendLineInnerAsync(string path, string line)\r\n{\r\n    using (FileStream stream = GetAsyncStream(path))\r\n    {\r\n        stream.Seek(0, SeekOrigin.End);\r\n        byte&#x5B;] buffer = Encoding.UTF8.GetBytes(line + Environment.NewLine);\r\n        await stream.WriteAsync(buffer, 0, buffer.Length);\r\n    }\r\n}\r\n<\/pre>\n<p>Now the null argument case will throw directly:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nSystem.ArgumentNullException: Value cannot be null.\r\nParameter name: path\r\n   at ConsoleApplication1.Program.Main(String&#x5B;] args)\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>In a very early post, I stated: An &#8216;async&#8217; method is not free. The compiler does some complex code generation steps to morph your method into a proper asynchronous state machine with all the associated exception handling logic, management of&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21],"tags":[],"class_list":["post-2371","post","type-post","status-publish","format-standard","hentry","category-async"],"_links":{"self":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/2371","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2371"}],"version-history":[{"count":0,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/2371\/revisions"}],"wp:attachment":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2371"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2371"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2371"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}