{"id":1075,"date":"2018-01-11T13:29:45","date_gmt":"2018-01-11T05:29:45","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/seteplia\/?p=1075"},"modified":"2022-07-08T13:11:14","modified_gmt":"2022-07-08T20:11:14","slug":"extending-the-async-methods-in-c","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/extending-the-async-methods-in-c\/","title":{"rendered":"Extending the async methods in C#"},"content":{"rendered":"<p><strong>The async series<\/strong><\/p>\n<ul>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/premier-developer\/dissecting-the-async-methods-in-c\/\">Dissecting the async methods in C#<\/a>.<\/li>\n<li><strong>Extending the async methods in C#<\/strong>.<\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/premier-developer\/the-performance-characteristics-of-async-methods\/\">The performance characteristics of the async methods in C#<\/a>.<\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/premier-developer\/\/one-user-scenario-to-rule-them-all\/\">One user scenario to rule them all<\/a>.<\/li>\n<\/ul>\n<p>In the <a href=\"https:\/\/devblogs.microsoft.com\/premier-developer\/dissecting-the-async-methods-in-c\/\">previous blog post<\/a> we discussed how the C# compiler transforms asynchronous methods. In this post, we&#8217;ll focus on extensibility points the C# compiler provides for customizing the behavior of async methods.<\/p>\n<p>There are 3 ways how you can control the async method&#8217;s machinery:<\/p>\n<ol>\n<li>Provide your own async method builder in the <code>System.Runtime.CompilerServices<\/code> namespace.<\/li>\n<li>Use custom task awaiters.<\/li>\n<li>Define your own task-like types.<\/li>\n<\/ol>\n<h4>Custom types fromm <code>System.Runtime.CompilerServices<\/code> namespace<\/h4>\n<p>As we know from the previous post, the C# compiler transforms async methods into a generated state machine that relies on some predefined types. But the C# compiler does not expect that these well-known types come from a specific assembly. For instance, you can provide your own implementation of <a href=\"http:\/\/referencesource.microsoft.com\/#mscorlib\/system\/runtime\/compilerservices\/AsyncMethodBuilder.cs,b07562c618ee846c\"><code>AsyncVoidMethodBuilder<\/code><\/a> in your project and the C# compiler will &#8220;bind&#8221; async machinery to your custom type.<\/p>\n<p>This is a good way to explore what the underlying transformations are and to see what&#8217;s happening at runtime:<\/p>\n<pre class=\"lang:default decode:true \">namespace System.Runtime.CompilerServices\r\n{\r\n    \/\/ AsyncVoidMethodBuilder.cs in your project\r\n    public class AsyncVoidMethodBuilder\r\n    {\r\n        public AsyncVoidMethodBuilder()\r\n            =&gt; Console.WriteLine(\".ctor\");\r\n \r\n        public static AsyncVoidMethodBuilder Create()\r\n            =&gt; new AsyncVoidMethodBuilder();\r\n \r\n        public void SetResult() =&gt; Console.WriteLine(\"SetResult\");\r\n \r\n        public void Start&lt;TStateMachine&gt;(ref TStateMachine stateMachine)\r\n            where TStateMachine : IAsyncStateMachine\r\n        {\r\n            Console.WriteLine(\"Start\");\r\n            stateMachine.MoveNext();\r\n        }\r\n \r\n        \/\/ AwaitOnCompleted, AwaitUnsafeOnCompleted, SetException \r\n        \/\/ and SetStateMachine are empty\r\n    }   \r\n}<\/pre>\n<p>Now, every async method in your project will use the custom version of <code>AsyncVoidMethodBuilder<\/code>. We can test this with a simple async method:<\/p>\n<pre class=\"lang:default decode:true \">[Test]\r\npublic void RunAsyncVoid()\r\n{\r\n    Console.WriteLine(\"Before VoidAsync\");\r\n    VoidAsync();\r\n    Console.WriteLine(\"After VoidAsync\");\r\n \r\n    async void VoidAsync() { }\r\n}<\/pre>\n<p>The output of this test is:<\/p>\n<pre class=\"lang:default decode:true \">Before VoidAsync\r\n.ctor\r\nStart\r\nSetResult\r\nAfter VoidAsync<\/pre>\n<p>You can implement <code>UnsafeAwaitOnComplete<\/code> method to test the behavior of an async method with <code>await<\/code> clause that returns non-completed task as well. The full example can be found at <a href=\"https:\/\/github.com\/SergeyTeplyakov\/EduAsync\/blob\/master\/src\/01_AsyncVoidBuilder\/AsyncVoidSample.cs\">github<\/a>.<\/p>\n<p>To change the behavior for <code>async Task<\/code> and <code>async Task&lt;T&gt;<\/code> methods you should provide your own version of <a href=\"http:\/\/referencesource.microsoft.com\/#mscorlib\/system\/runtime\/compilerservices\/AsyncMethodBuilder.cs,c983aa3f7c40052f\"><code>AsyncTaskMethodBuilder<\/code><\/a> and <a href=\"http:\/\/referencesource.microsoft.com\/#mscorlib\/system\/runtime\/compilerservices\/AsyncMethodBuilder.cs,5916df9e324fc0a1\"><code>AsyncTaskMethodBuilder&lt;T&gt;<\/code><\/a><\/p>\n<p>The full example with these types can be found at my github project called <a href=\"https:\/\/github.com\/SergeyTeplyakov\/EduAsync\">EduAsync<\/a> (*) in <a href=\"https:\/\/github.com\/SergeyTeplyakov\/EduAsync\/blob\/master\/src\/02_AsyncTaskBuilder\/AsyncTaskMethodBuilder.cs\">AsyncTaskBuilder.cs<\/a> and <a href=\"https:\/\/github.com\/SergeyTeplyakov\/EduAsync\/blob\/master\/src\/03_AsyncTaskBuilderOfT\/AsyncTaskMethodBuilderOfT.cs\">AsyncTaskMethodBuilderOfT.cs<\/a> respectively.<\/p>\n<p>(*) Thanks <a href=\"https:\/\/codeblog.jonskeet.uk\/category\/eduasync\/\">Jon Skeet<\/a> for inspiration for this project. This is a really good way to learn async machinery deeper.<\/p>\n<h4>Custom awaiters<\/h4>\n<p>The previous example is &#8220;hacky&#8221; and not suitable for production. We can learn the async machinery that way, but you definitely don&#8217;t want to see such a code in your codebase. The C# language authors built-in proper extensibility points into the compiler that allows to &#8220;await&#8221; different types in async methods.<\/p>\n<p>In order for a type to be &#8220;awaitable&#8221; (i.e. to be valid in the context of an <code>await<\/code> expression) the type should follow a special pattern:<\/p>\n<ul>\n<li>Compiler should be able to find an instance or an extension method called <code>GetAwaiter<\/code>. The return type of this method should follow certain requirements:<\/li>\n<li>The type should implement <a href=\"http:\/\/referencesource.microsoft.com\/#mscorlib\/system\/runtime\/compilerservices\/INotifyCompletion.cs,23\"><code>INotifyCompletion<\/code><\/a> interface.<\/li>\n<li>The type should have <code>bool IsCompleted {get;}<\/code> property and <code>T GetResult()<\/code> method.<\/li>\n<\/ul>\n<p>This means that we can easily make <code>Lazy&lt;T&gt;<\/code> awaitable:<\/p>\n<pre class=\"lang:default decode:true \">public struct LazyAwaiter&lt;T&gt; : INotifyCompletion\r\n{\r\n    private readonly Lazy&lt;T&gt; _lazy;\r\n \r\n    public LazyAwaiter(Lazy&lt;T&gt; lazy) =&gt; _lazy = lazy;\r\n \r\n    public T GetResult() =&gt; _lazy.Value;\r\n \r\n    public bool IsCompleted =&gt; true;\r\n \r\n    public void OnCompleted(Action continuation) { }\r\n}\r\n \r\npublic static class LazyAwaiterExtensions\r\n{\r\n    public static LazyAwaiter&lt;T&gt; GetAwaiter&lt;T&gt;(this Lazy&lt;T&gt; lazy)\r\n    {\r\n        return new LazyAwaiter&lt;T&gt;(lazy);\r\n    }\r\n}<\/pre>\n<pre class=\"lang:default decode:true \">public static async Task Foo()\r\n{\r\n    var lazy = new Lazy&lt;int&gt;(() =&gt; 42);\r\n    var result = await lazy;\r\n    Console.WriteLine(result);\r\n}<\/pre>\n<p>The example could be looked too contrived but this extensibility point is actually very helpful and is used in the wild. For instance, <a href=\"https:\/\/github.com\/Reactive-Extensions\/Rx.NET\">Reactive Extensions for .NET<\/a> provides a <a href=\"https:\/\/github.com\/Reactive-Extensions\/Rx.NET\/blob\/fa1629a1e12a8fc21c95aeff7863425c2485defd\/Rx.NET\/Source\/src\/System.Reactive\/Linq\/Observable.Awaiter.cs#L21\">custom awaiter<\/a> for awaiting <code>IObservable&lt;T&gt;<\/code> instances in async methods. The BCL itself has <a href=\"http:\/\/referencesource.microsoft.com\/#mscorlib\/system\/runtime\/compilerservices\/YieldAwaitable.cs,45\"><code>YieldAwaitable<\/code><\/a> used by <a href=\"http:\/\/referencesource.microsoft.com\/#mscorlib\/system\/threading\/Tasks\/Task.cs,3031\"><code>Task.Yield<\/code><\/a>and <a href=\"http:\/\/referencesource.microsoft.com\/#mscorlib\/system\/security\/cryptography\/cryptostream.cs,328\"><code>HopToThreadPoolAwaitable<\/code><\/a>:<\/p>\n<pre class=\"lang:default decode:true \">public struct HopToThreadPoolAwaitable : INotifyCompletion\r\n{\r\n    public HopToThreadPoolAwaitable GetAwaiter() =&gt; this;\r\n    public bool IsCompleted =&gt; false;\r\n \r\n    public void OnCompleted(Action continuation) =&gt; Task.Run(continuation);\r\n    public void GetResult() { }\r\n}<\/pre>\n<p>The following unit test demonstrates the last awaiter in action:<\/p>\n<pre class=\"lang:default decode:true \">[Test]\r\npublic async Task Test()\r\n{\r\n    var testThreadId = Thread.CurrentThread.ManagedThreadId;\r\n    await Sample();\r\n \r\n    async Task Sample()\r\n    {\r\n        Assert.AreEqual(Thread.CurrentThread.ManagedThreadId, testThreadId);\r\n \r\n        await default(HopToThreadPoolAwaitable);\r\n        Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, testThreadId);\r\n    }\r\n}<\/pre>\n<p>The first part of any &#8220;async&#8221; method (before the first <code>await<\/code> statement) runs synchronously. In most cases, this is fine and desirable for eager argument validation, but sometimes we would like to make sure that the method body would not block the caller&#8217;s thread. <code>HopToThreadPoolAwaitable<\/code> makes sure that the rest of the method is executed in the thread pool thread rather than in the caller&#8217;s thread.<\/p>\n<h4>Task-like types<\/h4>\n<p>Custom awaiters were available from the very first version of the compiler that supported async\/await (i.e. from C# 5). This extensibility point is very useful but limited because all the async methods should&#8217;ve returned <code>void<\/code>, <code>Task<\/code> or <code>Task&lt;T&gt;<\/code>. Starting from C# 7.2 the compiler support task-like types.<\/p>\n<p><a href=\"https:\/\/github.com\/dotnet\/roslyn\/blob\/master\/docs\/features\/task-types.md\">Task-like type<\/a> is a class or a struct with an associated <em>builder type<\/em> identified by <code>AsyncMethodBuilderAttribute<\/code> (**). To make the task-like type useful it should be <em>awaitable<\/em> in a way we describe in the previous section. Basically, task-like types combine the first two extensibility points described before by making the first way officially supported one.<\/p>\n<p>(**) Today you have to define this attribute yourself. The example can be found at <a href=\"https:\/\/github.com\/SergeyTeplyakov\/EduAsync\/blob\/master\/src\/07_CustomTaskLikeTypes\/AsyncMethodBuilder.cs#L9\">my github repo<\/a>.<\/p>\n<p>Here is a simple example of a custom task-like type defined as a struct:<\/p>\n<pre class=\"lang:default decode:true \">public sealed class TaskLikeMethodBuilder\r\n{\r\n    public TaskLikeMethodBuilder()\r\n        =&gt; Console.WriteLine(\".ctor\");\r\n \r\n    public static TaskLikeMethodBuilder Create()\r\n        =&gt; new TaskLikeMethodBuilder();\r\n \r\n    public void SetResult() =&gt; Console.WriteLine(\"SetResult\");\r\n \r\n    public void Start&lt;TStateMachine&gt;(ref TStateMachine stateMachine)\r\n        where TStateMachine : IAsyncStateMachine\r\n    {\r\n        Console.WriteLine(\"Start\");\r\n        stateMachine.MoveNext();\r\n    }\r\n \r\n    public TaskLike Task =&gt; default(TaskLike);\r\n \r\n    \/\/ AwaitOnCompleted, AwaitUnsafeOnCompleted, SetException \r\n    \/\/ and SetStateMachine are empty\r\n\r\n}\r\n \r\n[System.Runtime.CompilerServices.AsyncMethodBuilder(typeof(TaskLikeMethodBuilder))]\r\npublic struct TaskLike\r\n{\r\n    public TaskLikeAwaiter GetAwaiter() =&gt; default(TaskLikeAwaiter);\r\n}\r\n \r\npublic struct TaskLikeAwaiter : INotifyCompletion\r\n{\r\n    public void GetResult() { }\r\n \r\n    public bool IsCompleted =&gt; true;\r\n \r\n    public void OnCompleted(Action continuation) { }\r\n}<\/pre>\n<p>And now we can define a method that returns <code>TaskLike<\/code> type and even use different task-like types in the method body:<\/p>\n<pre class=\"lang:default decode:true \">public async TaskLike FooAsync()\r\n{\r\n    await Task.Yield();\r\n    await default(TaskLike);\r\n}<\/pre>\n<p>The main reason for having task-like types is an ability to reduce the overhead of async operations. Every async operation that returns <code>Task&lt;T&gt;<\/code>allocates at least one object in the managed heap &#8211; the task itself. This is perfectly fine for a vast majority of applications especially when they deal with coarse-grained async operations. But this is not the case for infrastructure-level code that could span thousands of small tasks per second. For such kind of scenarios reducing one allocation per call could reasonably increase performance.<\/p>\n<h4>Async pattern extensibility 101<\/h4>\n<ul>\n<li>The C# compiler provides various ways for extending async methods.<\/li>\n<li>You can change the behavior for existing Task-based async methods by providing your own version of <code>AsyncTaskMethodBuilder<\/code> type.<\/li>\n<li>You can make a type &#8220;awaitable&#8221; by implementing &#8220;awaitable pattern&#8221;.<\/li>\n<li>Starting from C# 7 you can build your own task-like types.<\/li>\n<\/ul>\n<h4>Additional references<\/h4>\n<ul>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/premier-developer\/dissecting-the-async-methods-in-c\/\">Dissecting the async methods in C#<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/SergeyTeplyakov\/EduAsync\/\">EduAsync repo<\/a> on github.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/roslyn\/blob\/master\/docs\/features\/task-types.md\">Task-like types<\/a><\/li>\n<\/ul>\n<p>Next time we&#8217;ll discuss the perf characteristics of async methods and will see how the newest task-like value type called <code>System.ValueTask<\/code> affects performance.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The async series Dissecting the async methods in C#. Extending the async methods in C#. The performance characteristics of the async methods in C#. One user scenario to rule them all. In the previous blog post we discussed how the C# compiler transforms asynchronous methods. In this post, we&#8217;ll focus on extensibility points the C# [&hellip;]<\/p>\n","protected":false},"author":4004,"featured_media":37840,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[6700],"tags":[6695],"class_list":["post-1075","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net-internals","tag-seteplia"],"acf":[],"blog_post_summary":"<p>The async series Dissecting the async methods in C#. Extending the async methods in C#. The performance characteristics of the async methods in C#. One user scenario to rule them all. In the previous blog post we discussed how the C# compiler transforms asynchronous methods. In this post, we&#8217;ll focus on extensibility points the C# [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/1075","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/4004"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=1075"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/1075\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/37840"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=1075"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=1075"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=1075"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}