smart-interactive-display/Assets/Plugins/AsyncAwaitUtil/Documentation/ReadMe.html

470 lines
92 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<!-- saved from url=(0085)http://www.stevevermeulen.com/index.php/2017/09/23/using-async-await-in-unity3d-2017/ -->
<html lang="en-US"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="profile" href="http://gmpg.org/xfn/11">
<title>How to use Async-Await instead of coroutines in Unity3d 2017 | Steve Vermeulen</title>
<!-- All in One SEO Pack 2.3.16 by Michael Torbert of Semper Fi Web Design[187,265] -->
<link rel="canonical" href="http://www.stevevermeulen.com/index.php/2017/09/23/using-async-await-in-unity3d-2017/">
<!-- /all in one seo pack -->
<link rel="dns-prefetch" href="http://cdn.jsdelivr.net/">
<link rel="dns-prefetch" href="http://s.w.org/">
<link rel="alternate" type="application/rss+xml" title="Steve Vermeulen » Feed" href="http://www.stevevermeulen.com/index.php/feed/">
<link rel="alternate" type="application/rss+xml" title="Steve Vermeulen » Comments Feed" href="http://www.stevevermeulen.com/index.php/comments/feed/">
<link rel="alternate" type="application/rss+xml" title="Steve Vermeulen » Async-Await instead of coroutines in Unity 2017 Comments Feed" href="http://www.stevevermeulen.com/index.php/2017/09/23/using-async-await-in-unity3d-2017/feed/">
<script type="text/javascript">
window._wpemojiSettings = {"baseUrl":"https:\/\/s.w.org\/images\/core\/emoji\/2.3\/72x72\/","ext":".png","svgUrl":"https:\/\/s.w.org\/images\/core\/emoji\/2.3\/svg\/","svgExt":".svg","source":{"concatemoji":"http:\/\/www.stevevermeulen.com\/wp-includes\/js\/wp-emoji-release.min.js?ver=4.8.2"}};
!function(a,b,c){function d(a){var b,c,d,e,f=String.fromCharCode;if(!k||!k.fillText)return!1;switch(k.clearRect(0,0,j.width,j.height),k.textBaseline="top",k.font="600 32px Arial",a){case"flag":return k.fillText(f(55356,56826,55356,56819),0,0),b=j.toDataURL(),k.clearRect(0,0,j.width,j.height),k.fillText(f(55356,56826,8203,55356,56819),0,0),c=j.toDataURL(),b!==c&&(k.clearRect(0,0,j.width,j.height),k.fillText(f(55356,57332,56128,56423,56128,56418,56128,56421,56128,56430,56128,56423,56128,56447),0,0),b=j.toDataURL(),k.clearRect(0,0,j.width,j.height),k.fillText(f(55356,57332,8203,56128,56423,8203,56128,56418,8203,56128,56421,8203,56128,56430,8203,56128,56423,8203,56128,56447),0,0),c=j.toDataURL(),b!==c);case"emoji4":return k.fillText(f(55358,56794,8205,9794,65039),0,0),d=j.toDataURL(),k.clearRect(0,0,j.width,j.height),k.fillText(f(55358,56794,8203,9794,65039),0,0),e=j.toDataURL(),d!==e}return!1}function e(a){var c=b.createElement("script");c.src=a,c.defer=c.type="text/javascript",b.getElementsByTagName("head")[0].appendChild(c)}var f,g,h,i,j=b.createElement("canvas"),k=j.getContext&&j.getContext("2d");for(i=Array("flag","emoji4"),c.supports={everything:!0,everythingExceptFlag:!0},h=0;h<i.length;h++)c.supports[i[h]]=d(i[h]),c.supports.everything=c.supports.everything&&c.supports[i[h]],"flag"!==i[h]&&(c.supports.everythingExceptFlag=c.supports.everythingExceptFlag&&c.supports[i[h]]);c.supports.everythingExceptFlag=c.supports.everythingExceptFlag&&!c.supports.flag,c.DOMReady=!1,c.readyCallback=function(){c.DOMReady=!0},c.supports.everything||(g=function(){c.readyCallback()},b.addEventListener?(b.addEventListener("DOMContentLoaded",g,!1),a.addEventListener("load",g,!1)):(a.attachEvent("onload",g),b.attachEvent("onreadystatechange",function(){"complete"===b.readyState&&c.readyCallback()})),f=c.source||{},f.concatemoji?e(f.concatemoji):f.wpemoji&&f.twemoji&&(e(f.twemoji),e(f.wpemoji)))}(window,document,window._wpemojiSettings);
</script><script src="./ReadMe_files/wp-emoji-release.min.js.download" type="text/javascript" defer=""></script>
<style type="text/css">
img.wp-smiley,
img.emoji {
display: inline !important;
border: none !important;
box-shadow: none !important;
height: 1em !important;
width: 1em !important;
margin: 0 .07em !important;
vertical-align: -0.1em !important;
background: none !important;
padding: 0 !important;
}
</style>
<link rel="stylesheet" id="bhari-core-css-css" href="./ReadMe_files/style.min.css" type="text/css" media="all">
<style id="bhari-core-css-inline-css" type="text/css">
.error404 .site-content, .page .site-content, .error404 .custom-headers, .page .custom-headers {max-width: 1100px; }.archive .site-content, .search .site-content, .blog .site-content, .archive .custom-headers, .search .custom-headers, .blog .custom-headers {max-width: 1100px; }.single .site-content, .single .custom-headers {max-width: 1100px; }
</style>
<link rel="stylesheet" id="font-awesome-css" href="./ReadMe_files/font-awesome.min.css" type="text/css" media="all">
<link rel="stylesheet" id="font-awesome-styles-css" href="./ReadMe_files/font-awesome.min(1).css" type="text/css" media="all">
<!--[if lte IE 7]>
<link rel='stylesheet' id='font-awesome-ie7-css' href='http://www.stevevermeulen.com/wp-content/plugins/font-awesome/assets/css/font-awesome-ie7.min.css?ver=3.2.1' type='text/css' media='all' />
<![endif]-->
<link rel="stylesheet" id="tablepress-default-css" href="./ReadMe_files/default.min.css" type="text/css" media="all">
<script type="text/javascript" src="./ReadMe_files/jquery.js.download"></script>
<script type="text/javascript" src="./ReadMe_files/jquery-migrate.min.js.download"></script>
<link rel="https://api.w.org/" href="http://www.stevevermeulen.com/index.php/wp-json/">
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://www.stevevermeulen.com/xmlrpc.php?rsd">
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://www.stevevermeulen.com/wp-includes/wlwmanifest.xml">
<meta name="generator" content="WordPress 4.8.2">
<link rel="shortlink" href="http://www.stevevermeulen.com/?p=53">
<link rel="alternate" type="application/json+oembed" href="http://www.stevevermeulen.com/index.php/wp-json/oembed/1.0/embed?url=http%3A%2F%2Fwww.stevevermeulen.com%2Findex.php%2F2017%2F09%2F23%2Fusing-async-await-in-unity3d-2017%2F">
<link rel="alternate" type="text/xml+oembed" href="http://www.stevevermeulen.com/index.php/wp-json/oembed/1.0/embed?url=http%3A%2F%2Fwww.stevevermeulen.com%2Findex.php%2F2017%2F09%2F23%2Fusing-async-await-in-unity3d-2017%2F&amp;format=xml">
<link rel="pingback" href="http://www.stevevermeulen.com/xmlrpc.php"> <style type="text/css">.recentcomments a{display:inline !important;padding:0 !important;margin:0 !important;}</style>
<link rel="stylesheet" type="text/css" href="./ReadMe_files/shCore.css"><link rel="stylesheet" type="text/css" href="./ReadMe_files/shThemeDefault.css"><style type="text/css" id="syntaxhighlighteranchor"></style>
<style type="text/css" id="wp-custom-css">
/*
You can add your own CSS here.
Click the help icon above to learn more.
*/
.site-info { display: none; } </style>
<style>#cVim-command-bar, #cVim-command-bar-mode, #cVim-command-bar-input, #cVim-command-bar-search-results,
.cVim-completion-item, .cVim-completion-item .cVim-full, .cVim-completion-item .cVim-left,
.cVim-completion-item .cVim-right {
font-family: Helvetica, Helvetica Neue, Neue, sans-serif, monospace, Arial;
font-size: 10pt !important;
-webkit-font-smoothing: antialiased !important;
}
#cVim-command-bar {
position: fixed;
z-index: 2147483646;
background-color: #1b1d1e;
color: #bbb;
display: none;
box-sizing: content-box;
box-shadow: 0 3px 3px rgba(0,0,0,0.4);
left: 0;
width: 100%;
height: 20px;
}
#cVim-command-bar-mode {
display: inline-block;
vertical-align: middle;
box-sizing: border-box;
padding-left: 2px;
height: 100%;
width: 10px;
padding-top: 2px;
color: #888;
}
#cVim-command-bar-input {
background-color: #1b1d1e;
color: #bbb;
height: 100%;
right: 0;
top: 0;
width: calc(100% - 10px);
position: absolute;
}
#cVim-command-bar-search-results {
position: fixed;
width: 100%;
overflow: hidden;
z-index: 2147483647;
left: 0;
box-shadow: 0 3px 3px rgba(0,0,0,0.4);
background-color: #1c1c1c;
}
.cVim-completion-item, .cVim-completion-item .cVim-full, .cVim-completion-item .cVim-left, .cVim-completion-item .cVim-right {
text-overflow: ellipsis;
padding: 1px;
display: inline-block;
box-sizing: border-box;
vertical-align: middle;
overflow: hidden;
white-space: nowrap;
}
.cVim-completion-item:nth-child(even) {
background-color: #1f1f1f;
}
.cVim-completion-item {
width: 100%; left: 0;
color: #bcbcbc;
}
.cVim-completion-item[active] {
width: 100%; left: 0;
color: #1b1d1e;
background-color: #f1f1f1;
}
.cVim-completion-item[active] span {
color: #1b1d1e;
}
.cVim-completion-item .cVim-left {
color: #fff;
width: 37%;
}
.cVim-completion-item .cVim-right {
font-style: italic;
color: #888;
width: 57%;
}
#cVim-link-container, .cVim-link-hint,
#cVim-hud, #cVim-status-bar {
font-family: Helvetica, Helvetica Neue, Neue, sans-serif, monospace, Arial;
font-size: 10pt !important;
-webkit-font-smoothing: antialiased !important;
}
#cVim-link-container {
position: absolute;
pointer-events: none;
width: 100%; left: 0;
height: 100%; top: 0;
z-index: 2147483647;
}
.cVim-link-hint {
position: absolute;
color: #302505 !important;
background-color: #ffd76e !important;
border-radius: 2px !important;
padding: 2px !important;
font-size: 8pt !important;
font-weight: 500 !important;
text-transform: uppercase !important;
border: 1px solid #ad810c;
display: inline-block !important;
vertical-align: middle !important;
text-align: center !important;
box-shadow: 2px 2px 1px rgba(0,0,0,0.25) !important;
}
.cVim-link-hint_match {
color: #777;
text-transform: uppercase !important;
}
#cVim-hud {
background-color: rgba(28,28,28,0.9);
position: fixed !important;
transition: right 0.2s ease-out;
z-index: 24724289;
}
#cVim-hud span {
padding: 2px;
padding-left: 4px;
padding-right: 4px;
color: #8f8f8f;
font-size: 10pt;
}
#cVim-frames-outline {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
right: 0;
z-index: 9999999999;
box-sizing: border-box;
border: 3px solid yellow;
}
</style></head>
<body class="post-template-default single single-post postid-53 single-format-standard layout-no-sidebar">
<div id="page" class="site">
<a class="skip-link screen-reader-text" href="http://www.stevevermeulen.com/index.php/2017/09/23/using-async-await-in-unity3d-2017/#content" data-slimstat="5">Skip to content</a>
<nav id="site-navigation" class="main-navigation" role="navigation">
<button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false">
<i class="fa fa-reorder" aria-hidden="true"></i>
Primary Menu </button>
<div class="menu-menu-1-container"></div> </nav><!-- #site-navigation -->
</header><!-- #masthead -->
<div id="content" class="site-content">
<div id="primary" class="content-area">
<main id="main" class="site-main" role="main">
<article id="post-53" class="post-53 post type-post status-publish format-standard hentry category-unity3d tag-async tag-async-await tag-await tag-c tag-coroutines tag-csharp tag-events tag-game-development tag-ienumerator tag-programming tag-software tag-unirx tag-unity3d">
<header class="entry-header">
<h1 class="entry-title">Async-Await instead of coroutines in Unity 2017</h1><div class="entry-meta"><span class="meta-author"><img alt="" src="./ReadMe_files/22d474190b1889d3373fa4f9334e979c" srcset="http://2.gravatar.com/avatar/22d474190b1889d3373fa4f9334e979c?s=40&amp;d=mm&amp;r=g 2x" class="avatar avatar-20 photo" height="20" width="20"><span class="byline"><span class="author vcard"><a class="url fn n" href="http://www.stevevermeulen.com/index.php/author/svermeulen/" data-slimstat="5">svermeulen</a></span> </span></span><span class="sep">/</span><span class="meta-date"><i class="fa fa-calendar" aria-hidden="true"></i> <span class="posted-on"><a href="http://www.stevevermeulen.com/index.php/2017/09/23/using-async-await-in-unity3d-2017/" rel="bookmark" data-slimstat="5"><time class="entry-date published" datetime="2017-09-23T07:15:03+00:00">September 23, 2017</time><time class="updated" datetime="2017-09-27T08:57:50+00:00">September 27, 2017</time></a> </span></span></div><!-- .entry-meta -->
</header><!-- .entry-header -->
<div class="entry-content">
<p>Note: For the most up-to-date version of this document see the <a href="http://www.stevevermeulen.com/index.php/2017/09/23/using-async-await-in-unity3d-2017/">online version</a></p>
<p>Using coroutines in Unity is often a great way to solve certain problems, however it comes with certain drawbacks as well:</p>
<ol>
<li>Coroutines cant return values. This encourages programmers to create huge monolithic coroutine methods instead of composing them out of many smaller methods. Some workarounds exist, such as passing a callback parameter of type Action&lt;&gt; to the coroutine, or casting the final untyped value that is yielded from the coroutine after it completes, but these approaches are awkward to use and error prone.</li>
<li>Coroutines make error handling difficult. You cannot put a yield inside a try-catch, so it is not possible to handle exceptions. Also, when exceptions do occur the stack trace only tells you the coroutine where the exception was thrown, so you have to guess which other coroutines it might have been called from.</li>
</ol>
<span class="" style="display:block;clear:both;height: 0px;padding-top: 30px;border-top-width:0px;border-bottom-width:0px;"></span>
<p>With the release of Unity 2017, it is now possible to use a new C# feature called async-await for our asynchronous methods instead. This comes with a lot of nice features compared to coroutines.</p>
<p>To enable this feature, all you need to do is open your player settings (Edit -&gt; Project Settings -&gt; Player) and change “Scripting Runtime Version” to “Experimental (.NET 4.6 Equivalent).</p>
<p>Lets look at a simple example. Given the following coroutine:</p>
<div><div id="highlighter_801899" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AsyncExample : MonoBehaviour</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">IEnumerator Start()</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">Debug.Log(</code><code class="csharp string">"Waiting 1 second..."</code><code class="csharp plain">);</code></div><div class="line number6 index5 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">yield</code> <code class="csharp keyword">return</code> <code class="csharp keyword">new</code> <code class="csharp plain">WaitForSeconds(1.0f);</code></div><div class="line number7 index6 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">Debug.Log(</code><code class="csharp string">"Done!"</code><code class="csharp plain">);</code></div><div class="line number8 index7 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number9 index8 alt2"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>The equivalent way to do this using async-await would be the following:</p>
<div><div id="highlighter_536879" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AsyncExample : MonoBehaviour</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp keyword">void</code> <code class="csharp plain">Start()</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">Debug.Log(</code><code class="csharp string">"Waiting 1 second..."</code><code class="csharp plain">);</code></div><div class="line number6 index5 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp plain">Task.Delay(TimeSpan.FromSeconds(1));</code></div><div class="line number7 index6 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">Debug.Log(</code><code class="csharp string">"Done!"</code><code class="csharp plain">);</code></div><div class="line number8 index7 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number9 index8 alt2"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>Its helpful to be somewhat aware of whats happening under-the-hood in both these cases.</p>
<p>In short, <a href="http://altdevblog.com/2011/07/07/unity3d-coroutines-in-detail/" data-slimstat="5">Unity coroutines are implemented using C#s built-in support for iterator blocks</a>. The IEnumerator iterator object that you provide to the StartCoroutine method is saved by Unity and each frame this iterator object is advanced forward to get new values that are yielded by your coroutine. The different values that you yield return are then read by Unity to trigger special case behaviour, like executing a nested coroutine (when returning another IEnumerator), delaying by some number of seconds (when returning an instance of type WaitForSeconds), or just waiting until the next frame (when returning null).</p>
<p>Unfortunately, due to the fact that async-await is quite new within Unity, this built-in support for coroutines as explained above does not exist in a similar fashion for async-await. Which means that we have to add a lot of this support ourselves.</p>
<p>Unity does provide one important piece for us however. As you can see in the above example, our async methods will be run on the main unity thread by default. In non-unity C# applications, async methods are often automatically run on separate threads, which would be a big problem in Unity since we would not always be able to interact with the Unity API in these cases. Without this support from the Unity engine, our calls to Unity methods/objects inside our async methods would sometimes fail because they would be executed on a separate thread. Under the hood it works this way because Unity has provided a default SynchronizationContext called UnitySynchronizationContext which automatically collects any async code that is queued each frame and continues running them on the main unity thread.</p>
<p>As it turns out, however, this is enough to get us started with using async-await! We just need a bit of helper code to allow us to do some more interesting things than just simple time delays.</p>
<h2>Custom Awaiters</h2>
<p>Currently, theres not a lot of interesting async code we can write. We can call other async methods, and we can use Task.Delay, like in the example above, but not much else.</p>
<p>As a simple example, lets add the ability to directly await on a TimeSpan instead of always having to call Task.Delay every time like the example above. Like this:</p>
<div><div id="highlighter_556374" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AsyncExample : MonoBehaviour</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp keyword">void</code> <code class="csharp plain">Start()</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp plain">TimeSpan.FromSeconds(1);</code></div><div class="line number6 index5 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number7 index6 alt2"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>All we need to do to support this is to simply add a custom GetAwaiter extension method to the TimeSpan class:</p>
<div><div id="highlighter_949510" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">public</code> <code class="csharp keyword">static</code> <code class="csharp keyword">class</code> <code class="csharp plain">AwaitExtensions</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">public</code> <code class="csharp keyword">static</code> <code class="csharp plain">TaskAwaiter GetAwaiter(</code><code class="csharp keyword">this</code> <code class="csharp plain">TimeSpan timeSpan)</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">return</code> <code class="csharp plain">Task.Delay(timeSpan).GetAwaiter();</code></div><div class="line number6 index5 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number7 index6 alt2"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>This works because in order to support awaiting a given object in newer versions of C#, all thats needed is that the object has a method named GetAwaiter that returns an Awaiter object. This is great because it allows us to await anything we want, by using an extension method like above, without needing to change the actual TimeSpan class.</p>
<p>We can use this same approach to support awaiting other types of objects too, including all of the classes that Unity uses for coroutine instructions! We can make WaitForSeconds, WaitForFixedUpdate, WWW, etc all awaitable in the same way that they are yieldable within coroutines. We can also add a GetAwaiter method to IEnumerator to support awaiting coroutines to allow interchanging async code with old IEnumerator code.</p>
<p>The code to make all this happen can be downloaded from <a href="https://github.com/svermeulen/Unity3dAsyncAwaitUtil/releases" data-slimstat="5">the releases section of the github repo</a>. This allows you to do things like the following:</p>
<div><div id="highlighter_809019" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div><div class="line number13 index12 alt2">13</div><div class="line number14 index13 alt1">14</div><div class="line number15 index14 alt2">15</div><div class="line number16 index15 alt1">16</div><div class="line number17 index16 alt2">17</div><div class="line number18 index17 alt1">18</div><div class="line number19 index18 alt2">19</div><div class="line number20 index19 alt1">20</div><div class="line number21 index20 alt2">21</div><div class="line number22 index21 alt1">22</div><div class="line number23 index22 alt2">23</div><div class="line number24 index23 alt1">24</div><div class="line number25 index24 alt2">25</div><div class="line number26 index25 alt1">26</div><div class="line number27 index26 alt2">27</div><div class="line number28 index27 alt1">28</div><div class="line number29 index28 alt2">29</div><div class="line number30 index29 alt1">30</div><div class="line number31 index30 alt2">31</div><div class="line number32 index31 alt1">32</div><div class="line number33 index32 alt2">33</div><div class="line number34 index33 alt1">34</div><div class="line number35 index34 alt2">35</div><div class="line number36 index35 alt1">36</div><div class="line number37 index36 alt2">37</div><div class="line number38 index37 alt1">38</div><div class="line number39 index38 alt2">39</div><div class="line number40 index39 alt1">40</div><div class="line number41 index40 alt2">41</div><div class="line number42 index41 alt1">42</div><div class="line number43 index42 alt2">43</div><div class="line number44 index43 alt1">44</div><div class="line number45 index44 alt2">45</div><div class="line number46 index45 alt1">46</div><div class="line number47 index46 alt2">47</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AsyncExample : MonoBehaviour</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">public</code> <code class="csharp keyword">async</code> <code class="csharp keyword">void</code> <code class="csharp plain">Start()</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// Wait one second</code></div><div class="line number6 index5 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp keyword">new</code> <code class="csharp plain">WaitForSeconds(1.0f);</code></div><div class="line number7 index6 alt2">&nbsp;</div><div class="line number8 index7 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// Wait for IEnumerator to complete</code></div><div class="line number9 index8 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp plain">CustomCoroutineAsync();</code></div><div class="line number10 index9 alt1">&nbsp;</div><div class="line number11 index10 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp plain">LoadModelAsync();</code></div><div class="line number12 index11 alt1">&nbsp;</div><div class="line number13 index12 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// You can also get the final yielded value from the coroutine</code></div><div class="line number14 index13 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">var</code> <code class="csharp plain">value = (</code><code class="csharp keyword">string</code><code class="csharp plain">)(</code><code class="csharp keyword">await</code> <code class="csharp plain">CustomCoroutineWithReturnValue());</code></div><div class="line number15 index14 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// value is equal to "asdf" here</code></div><div class="line number16 index15 alt1">&nbsp;</div><div class="line number17 index16 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// Open notepad and wait for the user to exit</code></div><div class="line number18 index17 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">var</code> <code class="csharp plain">returnCode = </code><code class="csharp keyword">await</code> <code class="csharp plain">Process.Start(</code><code class="csharp string">"notepad.exe"</code><code class="csharp plain">);</code></div><div class="line number19 index18 alt2">&nbsp;</div><div class="line number20 index19 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// Load another scene and wait for it to finish loading</code></div><div class="line number21 index20 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp plain">SceneManager.LoadSceneAsync(</code><code class="csharp string">"scene2"</code><code class="csharp plain">);</code></div><div class="line number22 index21 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number23 index22 alt2">&nbsp;</div><div class="line number24 index23 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp plain">Task LoadModelAsync()</code></div><div class="line number25 index24 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number26 index25 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">var</code> <code class="csharp plain">assetBundle = </code><code class="csharp keyword">await</code> <code class="csharp plain">GetAssetBundle(</code><code class="csharp string">"www.my-server.com/myfile"</code><code class="csharp plain">);</code></div><div class="line number27 index26 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">var</code> <code class="csharp plain">prefab = </code><code class="csharp keyword">await</code> <code class="csharp plain">assetBundle.LoadAssetAsync&lt;GameObject&gt;(</code><code class="csharp string">"myasset"</code><code class="csharp plain">);</code></div><div class="line number28 index27 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">GameObject.Instantiate(prefab);</code></div><div class="line number29 index28 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">assetBundle.Unload(</code><code class="csharp keyword">false</code><code class="csharp plain">);</code></div><div class="line number30 index29 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number31 index30 alt2">&nbsp;</div><div class="line number32 index31 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp plain">Task&lt;AssetBundle&gt; GetAssetBundle(</code><code class="csharp keyword">string</code> <code class="csharp plain">url)</code></div><div class="line number33 index32 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number34 index33 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">return</code> <code class="csharp plain">(</code><code class="csharp keyword">await</code> <code class="csharp keyword">new</code> <code class="csharp plain">WWW(url)).assetBundle</code></div><div class="line number35 index34 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number36 index35 alt1">&nbsp;</div><div class="line number37 index36 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">IEnumerator CustomCoroutineAsync()</code></div><div class="line number38 index37 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number39 index38 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">yield</code> <code class="csharp keyword">return</code> <code class="csharp keyword">new</code> <code class="csharp plain">WaitForSeconds(1.0f);</code></div><div class="line number40 index39 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number41 index40 alt2">&nbsp;</div><div class="line number42 index41 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">IEnumerator CustomCoroutineWithReturnValue()</code></div><div class="line number43 index42 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number44 index43 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">yield</code> <code class="csharp keyword">return</code> <code class="csharp keyword">new</code> <code class="csharp plain">WaitForSeconds(1.0f);</code></div><div class="line number45 index44 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">yield</code> <code class="csharp keyword">return</code> <code class="csharp string">"asdf"</code><code class="csharp plain">;</code></div><div class="line number46 index45 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number47 index46 alt2"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>As you can see, using async await like this can be very powerful, especially when you start composing multiple async methods together like in the LoadModelAsync method above.</p>
<p>Note that for async methods that return values, we use the generic version of Task and pass our return type as the generic argument like with the GetAssetBundle above.</p>
<p>Note also that using WaitForSeconds above is actually preferable to our TimeSpan extension method in most cases because WaitForSeconds will use the Unity game time whereas our TimeSpan extension method will always use real time (so it would not be affected by changes to Time.timeScale)</p>
<h2>Triggering Async Code and Exception Handling</h2>
<p>One thing you might have noticed with our code above is that some methods are defined async void and some are defined async Task. So when should you use one over the other?</p>
<p>The main difference here is that methods that are defined async void cannot be waited on by other async methods. This would suggest that we should always prefer to define our async methods with return type Task so that we can await on them.</p>
<p>The only exception to this rule is when you want to call an async method from non-async code. Take the following example:</p>
<div><div id="highlighter_460542" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div><div class="line number13 index12 alt2">13</div><div class="line number14 index13 alt1">14</div><div class="line number15 index14 alt2">15</div><div class="line number16 index15 alt1">16</div><div class="line number17 index16 alt2">17</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AsyncExample : MonoBehaviour</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">public</code> <code class="csharp keyword">void</code> <code class="csharp plain">OnGUI()</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">if</code> <code class="csharp plain">(GUI.Button(</code><code class="csharp keyword">new</code> <code class="csharp plain">Rect(100, 100, 100, 100), </code><code class="csharp string">"Start Task"</code><code class="csharp plain">))</code></div><div class="line number6 index5 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number7 index6 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">RunTaskAsync();</code></div><div class="line number8 index7 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number9 index8 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number10 index9 alt1">&nbsp;</div><div class="line number11 index10 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp plain">Task RunTaskAsync()</code></div><div class="line number12 index11 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number13 index12 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">Debug.Log(</code><code class="csharp string">"Started task..."</code><code class="csharp plain">);</code></div><div class="line number14 index13 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp keyword">new</code> <code class="csharp plain">WaitForSeconds(1.0f);</code></div><div class="line number15 index14 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">throw</code> <code class="csharp keyword">new</code> <code class="csharp plain">Exception();</code></div><div class="line number16 index15 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number17 index16 alt2"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>In this example, when the user clicks the button, we want to start our async method. This code will compile and run, however there is a major issue with it. If any exceptions occur within the RunTaskAsync method, they will happen silently. The exception will not be logged to the unity console.</p>
<p>This is because when exceptions occur in async methods returning Task, they are captured by the returned Task object instead of being thrown and handled by Unity. This behaviour exists for a good reason: To allow async code to work properly with try-catch blocks. Take the following code for example:</p>
<div><div id="highlighter_117572" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div><div class="line number13 index12 alt2">13</div><div class="line number14 index13 alt1">14</div><div class="line number15 index14 alt2">15</div><div class="line number16 index15 alt1">16</div><div class="line number17 index16 alt2">17</div><div class="line number18 index17 alt1">18</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">async</code> <code class="csharp plain">Task DoSomethingAsync()</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">var</code> <code class="csharp plain">task = DoSomethingElseAsync();</code></div><div class="line number4 index3 alt1">&nbsp;</div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">try</code></div><div class="line number6 index5 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number7 index6 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp plain">task;</code></div><div class="line number8 index7 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number9 index8 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">catch</code> <code class="csharp plain">(Exception e)</code></div><div class="line number10 index9 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number11 index10 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// do something</code></div><div class="line number12 index11 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number13 index12 alt2"><code class="csharp plain">}</code></div><div class="line number14 index13 alt1">&nbsp;</div><div class="line number15 index14 alt2"><code class="csharp keyword">async</code> <code class="csharp plain">Task DoSomethingElseAsync()</code></div><div class="line number16 index15 alt1"><code class="csharp plain">{</code></div><div class="line number17 index16 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">throw</code> <code class="csharp keyword">new</code> <code class="csharp plain">Exception();</code></div><div class="line number18 index17 alt1"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>Here, the exception is captured by the Task returned by the DoSomethingElseAsync method and is only re-thrown when it is awaited. As you can see, <a href="https://blogs.msdn.microsoft.com/pfxteam/2013/03/13/invoke-the-method-with-await-ugh/" data-slimstat="5">invoking async methods is distinct from awaiting on them</a>, which is why its necessary to have the Task object capture the exceptions.</p>
<p>So in our OnGUI example above, when the exception is thrown inside the RunTaskAsync method, it is captured by the returned Task object, and since nothing awaits on this Task, the exception does not get bubbled up to Unity and therefore is never logged to the console.</p>
<p>But that leaves us with the question of what to do in these cases where we want to call async methods from non-async code. In our example above, we want to start the RunTaskAsync async method from inside the OnGUI method and we dont care about waiting for it to complete, so we dont want to have to add an await just so that exceptions can be logged.</p>
<p>The rule of thumb to remember here is:</p>
<p><strong>Never call `async Task` methods without also awaiting on the returned Task. If you dont want to wait for the async behaviour to complete, you should call an `async void` method instead.</strong></p>
<p>So our example becomes:</p>
<div><div id="highlighter_725996" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div><div class="line number13 index12 alt2">13</div><div class="line number14 index13 alt1">14</div><div class="line number15 index14 alt2">15</div><div class="line number16 index15 alt1">16</div><div class="line number17 index16 alt2">17</div><div class="line number18 index17 alt1">18</div><div class="line number19 index18 alt2">19</div><div class="line number20 index19 alt1">20</div><div class="line number21 index20 alt2">21</div><div class="line number22 index21 alt1">22</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AsyncExample : MonoBehaviour</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">public</code> <code class="csharp keyword">void</code> <code class="csharp plain">OnGUI()</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">if</code> <code class="csharp plain">(GUI.Button(</code><code class="csharp keyword">new</code> <code class="csharp plain">Rect(100, 100, 100, 100), </code><code class="csharp string">"Start Task"</code><code class="csharp plain">))</code></div><div class="line number6 index5 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number7 index6 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">RunTask();</code></div><div class="line number8 index7 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number9 index8 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number10 index9 alt1">&nbsp;</div><div class="line number11 index10 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp keyword">void</code> <code class="csharp plain">RunTask()</code></div><div class="line number12 index11 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number13 index12 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp plain">RunTaskAsync();</code></div><div class="line number14 index13 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number15 index14 alt2">&nbsp;</div><div class="line number16 index15 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp plain">Task RunTaskAsync()</code></div><div class="line number17 index16 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number18 index17 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">Debug.Log(</code><code class="csharp string">"Started task..."</code><code class="csharp plain">);</code></div><div class="line number19 index18 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp keyword">new</code> <code class="csharp plain">WaitForSeconds(1.0f);</code></div><div class="line number20 index19 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">throw</code> <code class="csharp keyword">new</code> <code class="csharp plain">Exception();</code></div><div class="line number21 index20 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number22 index21 alt1"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>If you run this code again, you should now see that the exception is logged. This is because when the exception gets thrown during the await in the RunTask method, it bubbles up to Unity and gets logged to the console, because in that case there is no Task object to capture it instead.</p>
<p>Methods that are marked as `async void` represent the root level entry point for some async behaviour. A good way to think about them is that they are fire and forget tasks that go off and execute some number of things in the background while any calling code immediately continues on.</p>
<p>By the way, this is also a good reason to follow the convention of always using the suffix Async on async methods that return Task. This is standard practice in most code bases that use async-await. It is helpful in conveying the fact that the method should always be preceded by an await, but also allows you to create an `async void` counterpart for the method that does not include the suffix.</p>
<p>Also worth mentioning is that if you are compiling your code in visual studio, then you should receive warnings when you attempt to call an `async Task` method without an associated await, which is a great way to avoid this mistake.</p>
<p>As an alternative to creating your own async void method, you can also use a helper method (included with the source code associated with this article) that will perform the await for you. In this case our example would become:</p>
<div><div id="highlighter_829238" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div><div class="line number13 index12 alt2">13</div><div class="line number14 index13 alt1">14</div><div class="line number15 index14 alt2">15</div><div class="line number16 index15 alt1">16</div><div class="line number17 index16 alt2">17</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AsyncExample : MonoBehaviour</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">public</code> <code class="csharp keyword">void</code> <code class="csharp plain">OnGUI()</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">if</code> <code class="csharp plain">(GUI.Button(</code><code class="csharp keyword">new</code> <code class="csharp plain">Rect(100, 100, 100, 100), </code><code class="csharp string">"Start Task"</code><code class="csharp plain">))</code></div><div class="line number6 index5 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number7 index6 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">RunTaskAsync().WrapErrors();</code></div><div class="line number8 index7 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number9 index8 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number10 index9 alt1">&nbsp;</div><div class="line number11 index10 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp plain">Task RunTaskAsync()</code></div><div class="line number12 index11 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number13 index12 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">Debug.Log(</code><code class="csharp string">"Started task..."</code><code class="csharp plain">);</code></div><div class="line number14 index13 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp keyword">new</code> <code class="csharp plain">WaitForSeconds(1.0f);</code></div><div class="line number15 index14 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">throw</code> <code class="csharp keyword">new</code> <code class="csharp plain">Exception();</code></div><div class="line number16 index15 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number17 index16 alt2"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>The WrapErrors() method is simply a generic way to ensure that the Task gets awaited on, so that Unity will always receive any exceptions that are thrown. It simply does an await and thats it:</p>
<div><div id="highlighter_706730" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">static</code> <code class="csharp keyword">async</code> <code class="csharp keyword">void</code> <code class="csharp plain">WrapErrors(</code><code class="csharp keyword">this</code> <code class="csharp plain">Task task)</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp plain">task;</code></div><div class="line number4 index3 alt1"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<h2>Calling async from coroutines</h2>
<p>For some code bases, migrating away from coroutines to use async-await might seem like a daunting task. We can make this process simpler by allowing async-await to be adopted incrementally. In order to do this however, we not only need the ability to call IEnumerator code from async code but we also need to be able to call async code from IEnumerator code. Thankfully, we can add this very easily with yet another extension method:</p>
<div><div id="highlighter_789716" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div><div class="line number13 index12 alt2">13</div><div class="line number14 index13 alt1">14</div><div class="line number15 index14 alt2">15</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">static</code> <code class="csharp keyword">class</code> <code class="csharp plain">TaskExtensions</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">public</code> <code class="csharp keyword">static</code> <code class="csharp plain">IEnumerator AsIEnumerator(</code><code class="csharp keyword">this</code> <code class="csharp plain">Task task)</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">while</code> <code class="csharp plain">(!task.IsCompleted)</code></div><div class="line number6 index5 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number7 index6 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">yield</code> <code class="csharp keyword">return</code> <code class="csharp keyword">null</code><code class="csharp plain">;</code></div><div class="line number8 index7 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number9 index8 alt2">&nbsp;</div><div class="line number10 index9 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">if</code> <code class="csharp plain">(task.IsFaulted)</code></div><div class="line number11 index10 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number12 index11 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">throw</code> <code class="csharp plain">task.Exception;</code></div><div class="line number13 index12 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number14 index13 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number15 index14 alt2"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>Now we can call async methods from coroutines like this:</p>
<div><div id="highlighter_313348" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div><div class="line number13 index12 alt2">13</div><div class="line number14 index13 alt1">14</div><div class="line number15 index14 alt2">15</div><div class="line number16 index15 alt1">16</div><div class="line number17 index16 alt2">17</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AsyncExample : MonoBehaviour</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">public</code> <code class="csharp keyword">void</code> <code class="csharp plain">Start()</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">StartCoroutine(RunTask());</code></div><div class="line number6 index5 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number7 index6 alt2">&nbsp;</div><div class="line number8 index7 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">IEnumerator RunTask()</code></div><div class="line number9 index8 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number10 index9 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">yield</code> <code class="csharp keyword">return</code> <code class="csharp plain">RunTaskAsync().AsIEnumerator();</code></div><div class="line number11 index10 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number12 index11 alt1">&nbsp;</div><div class="line number13 index12 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp plain">Task RunTaskAsync()</code></div><div class="line number14 index13 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number15 index14 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// run async code</code></div><div class="line number16 index15 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number17 index16 alt2"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<h2>Multiple Threads</h2>
<p>We can also use async-await to execute multiple threads. You can do this in two ways. The first way is to use the ConfigureAwait method like this:</p>
<div><div id="highlighter_22414" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AsyncExample : MonoBehaviour</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp keyword">void</code> <code class="csharp plain">Start()</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// Here we are on the unity thread</code></div><div class="line number6 index5 alt1">&nbsp;</div><div class="line number7 index6 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp plain">Task.Delay(TimeSpan.FromSeconds(1.0f)).ConfigureAwait(</code><code class="csharp keyword">false</code><code class="csharp plain">);</code></div><div class="line number8 index7 alt1">&nbsp;</div><div class="line number9 index8 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// Here we may or may not be on the unity thread depending on how the task that we</code></div><div class="line number10 index9 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// execute before the ConfigureAwait is implemented</code></div><div class="line number11 index10 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number12 index11 alt1"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>As mentioned above, Unity provides something called a default SynchronizationContext, which will execute asynchronous code on the main Unity thread by default. The ConfigureAwait method allows us to override this behaviour, and so the result will be that the code below the await will no longer be guaranteed to run on the main Unity thread and will instead inherit the context from the task that we are executing, which in some cases might be what we want.</p>
<p>If you want to explicitly execute code on a background thread, you can also do this:</p>
<div><div id="highlighter_269256" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AsyncExample : MonoBehaviour</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp keyword">void</code> <code class="csharp plain">Start()</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// We are on the unity thread here</code></div><div class="line number6 index5 alt1">&nbsp;</div><div class="line number7 index6 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp keyword">new</code> <code class="csharp plain">WaitForBackgroundThread();</code></div><div class="line number8 index7 alt1">&nbsp;</div><div class="line number9 index8 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// We are now on a background thread</code></div><div class="line number10 index9 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// NOTE: Do not call any unity objects here or anything in the unity api!</code></div><div class="line number11 index10 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number12 index11 alt1"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>WaitForBackgroundThread is a class included in the source code for this post, and will do the work of starting a new thread and also ensuring that Unitys default SynchronizationContext behaviour is overridden.</p>
<p>What about returning to the Unity thread?</p>
<p>You can do this simply by awaiting any of the Unity specific objects that we created above. For example:</p>
<div><div id="highlighter_647151" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div><div class="line number13 index12 alt2">13</div><div class="line number14 index13 alt1">14</div><div class="line number15 index14 alt2">15</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AsyncExample : MonoBehaviour</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp keyword">void</code> <code class="csharp plain">Start()</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// Unity thread</code></div><div class="line number6 index5 alt1">&nbsp;</div><div class="line number7 index6 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp keyword">new</code> <code class="csharp plain">WaitForBackgroundThread();</code></div><div class="line number8 index7 alt1">&nbsp;</div><div class="line number9 index8 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// Background thread</code></div><div class="line number10 index9 alt1">&nbsp;</div><div class="line number11 index10 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp keyword">new</code> <code class="csharp plain">WaitForSeconds(1.0f);</code></div><div class="line number12 index11 alt1">&nbsp;</div><div class="line number13 index12 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// Unity thread again</code></div><div class="line number14 index13 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number15 index14 alt2"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>The included source code also provides a class WaitForUpdate() that you can use if you just want to return to the unity thread without any delay:</p>
<div><div id="highlighter_271510" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div><div class="line number11 index10 alt2">11</div><div class="line number12 index11 alt1">12</div><div class="line number13 index12 alt2">13</div><div class="line number14 index13 alt1">14</div><div class="line number15 index14 alt2">15</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AsyncExample : MonoBehaviour</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp keyword">void</code> <code class="csharp plain">Start()</code></div><div class="line number4 index3 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// Unity thread</code></div><div class="line number6 index5 alt1">&nbsp;</div><div class="line number7 index6 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp keyword">new</code> <code class="csharp plain">WaitForBackgroundThread();</code></div><div class="line number8 index7 alt1">&nbsp;</div><div class="line number9 index8 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// Background thread</code></div><div class="line number10 index9 alt1">&nbsp;</div><div class="line number11 index10 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp keyword">new</code> <code class="csharp plain">WaitForUpdate();</code></div><div class="line number12 index11 alt1">&nbsp;</div><div class="line number13 index12 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp comments">// Unity thread again</code></div><div class="line number14 index13 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number15 index14 alt2"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>Of course, if you do use background threads, you need to be very careful to avoid concurrency issues. However it can be worth it in a lot of cases to improve performance.</p>
<h2>Gotchas and Best Practices</h2>
<ul>
<li>Avoid async void in favour of async Task, except in fire and forget cases where you want to start async code from non-async code</li>
<li>Attach the suffix Async to all async methods which return Task. This is helpful in conveying the fact that it should always be preceded by an await and allows an async void counterpart to be added easily without conflict</li>
<li>Debugging async methods using breakpoints in visual studio doesnt work yet. However the “VS tools for Unity” team says that they are working on it, as indicated <a href="https://twitter.com/jbevain/status/900043560665235456" data-slimstat="5">here</a></li>
</ul>
<h2>UniRx</h2>
<p>Yet another way to do asynchronous logic is to use reactive programming with a library like <a href="https://github.com/neuecc/UniRx" data-slimstat="5">UniRx</a>. Personally I am a huge fan of this type of coding and use it extensively in many projects that Im involved with. And thankfully, it is very easy to use alongside async-await with just another custom awaiter. For example:</p>
<div><div id="highlighter_818334" class="syntaxhighlighter csharp"><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td class="gutter"><div class="line number1 index0 alt2">1</div><div class="line number2 index1 alt1">2</div><div class="line number3 index2 alt2">3</div><div class="line number4 index3 alt1">4</div><div class="line number5 index4 alt2">5</div><div class="line number6 index5 alt1">6</div><div class="line number7 index6 alt2">7</div><div class="line number8 index7 alt1">8</div><div class="line number9 index8 alt2">9</div><div class="line number10 index9 alt1">10</div></td><td class="code"><div class="container"><div class="line number1 index0 alt2"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AsyncExample : MonoBehaviour</code></div><div class="line number2 index1 alt1"><code class="csharp plain">{</code></div><div class="line number3 index2 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">public</code> <code class="csharp plain">Button TestButton;</code></div><div class="line number4 index3 alt1">&nbsp;</div><div class="line number5 index4 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">async</code> <code class="csharp keyword">void</code> <code class="csharp plain">Start()</code></div><div class="line number6 index5 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">{</code></div><div class="line number7 index6 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp keyword">await</code> <code class="csharp plain">TestButton.OnClickAsObservable();</code></div><div class="line number8 index7 alt1"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">Debug.Log(</code><code class="csharp string">"Clicked Button!"</code><code class="csharp plain">);</code></div><div class="line number9 index8 alt2"><code class="csharp spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><code class="csharp plain">}</code></div><div class="line number10 index9 alt1"><code class="csharp plain">}</code></div></div></td></tr></tbody></table></div></div>
<p>I find that UniRx observables serve a different purpose from long-running async methods/coroutines, so they naturally fit alongside a workflow using async-await like in the examples above. I wont go into detail here, because UniRx and reactive programming is a separate topic in itself, but I will say that once you get comfortable thinking about data flow in your application in terms of UniRx “streams”, there is no going back.</p>
<h2>Source Code</h2>
<p>You can download the source code that includes async-await support from <a href="https://github.com/svermeulen/Unity3dAsyncAwaitUtil/releases" data-slimstat="5">the releases section of the github repo</a>.</p>
<h2>Further Reading</h2>
<ul>
<li><a href="https://blog.stephencleary.com/2012/02/async-and-await.html" data-slimstat="5">Async and Await</a></li>
<li><a href="https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap" data-slimstat="5">Task-based Asynchronous Pattern document</a></li>
<li><a href="https://docs.microsoft.com/en-us/dotnet/standard/async-in-depth" data-slimstat="5">Async in depth</a></li>
<li><a href="http://msdn.microsoft.com/en-us/magazine/jj991977.aspx" data-slimstat="5">Best Practices in Asynchronous Programming</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/hh191443.aspx" data-slimstat="5">Official MSDN documentation</a></li>
<li><a href="http://altdevblog.com/2011/07/07/unity3d-coroutines-in-detail/" data-slimstat="5">Unity3d Coroutines In Detail</a>
</li><li><a href="https://github.com/neuecc/UniRx" data-slimstat="5">UniRx Reactive Extensions</a>
</li>
</ul></div><!-- .entry-content -->
<footer class="entry-footer">
<span class="meta-tag"><i class="fa fa-tags" aria-hidden="true"></i> <span class="tags-links"> <a href="http://www.stevevermeulen.com/index.php/tag/async/" rel="tag" data-slimstat="5">async</a>, <a href="http://www.stevevermeulen.com/index.php/tag/async-await/" rel="tag" data-slimstat="5">async await</a>, <a href="http://www.stevevermeulen.com/index.php/tag/await/" rel="tag" data-slimstat="5">await</a>, <a href="http://www.stevevermeulen.com/index.php/tag/c/" rel="tag" data-slimstat="5">c#</a>, <a href="http://www.stevevermeulen.com/index.php/tag/coroutines/" rel="tag" data-slimstat="5">coroutines</a>, <a href="http://www.stevevermeulen.com/index.php/tag/csharp/" rel="tag" data-slimstat="5">csharp</a>, <a href="http://www.stevevermeulen.com/index.php/tag/events/" rel="tag" data-slimstat="5">events</a>, <a href="http://www.stevevermeulen.com/index.php/tag/game-development/" rel="tag" data-slimstat="5">game development</a>, <a href="http://www.stevevermeulen.com/index.php/tag/ienumerator/" rel="tag" data-slimstat="5">ienumerator</a>, <a href="http://www.stevevermeulen.com/index.php/tag/programming/" rel="tag" data-slimstat="5">programming</a>, <a href="http://www.stevevermeulen.com/index.php/tag/software/" rel="tag" data-slimstat="5">software</a>, <a href="http://www.stevevermeulen.com/index.php/tag/unirx/" rel="tag" data-slimstat="5">unirx</a>, <a href="http://www.stevevermeulen.com/index.php/tag/unity3d/" rel="tag" data-slimstat="5">unity3d</a> </span></span>
</footer><!-- .entry-footer -->
</article><!-- #post-## -->
<div id="comments" class="comments-area">
<h2 class="comments-title">
One Reply to “Async-Await instead of coroutines in Unity 2017” </h2>
<ol class="comment-list">
<li id="comment-2" class="comment even thread-even depth-1">
<article id="div-comment-2" class="comment-body">
<footer class="comment-meta">
<div class="comment-author vcard">
<img alt="" src="./ReadMe_files/a276129472f6ad4719e01704016e6f73" srcset="http://1.gravatar.com/avatar/a276129472f6ad4719e01704016e6f73?s=64&amp;d=mm&amp;r=g 2x" class="avatar avatar-32 photo" height="32" width="32"> <b class="fn"><a href="https://github.com/zsaladin" rel="external nofollow" class="url" data-slimstat="5">zsaladin</a></b> <span class="says">says:</span> </div><!-- .comment-author -->
<div class="comment-metadata">
<a href="http://www.stevevermeulen.com/index.php/2017/09/23/using-async-await-in-unity3d-2017/#comment-2" data-slimstat="5">
<time datetime="2017-09-24T16:12:42+00:00">
September 24, 2017 at 4:12 pm </time>
</a>
</div><!-- .comment-metadata -->
</footer><!-- .comment-meta -->
<div class="comment-content">
<p>Cool!<br>
Its similar to my work.</p>
<p>FYI : <a href="https://github.com/zsaladin/Asyncoroutine" rel="nofollow" data-slimstat="5">https://github.com/zsaladin/Asyncoroutine</a></p>
</div><!-- .comment-content -->
<div class="reply"><a rel="nofollow" class="comment-reply-link" href="http://www.stevevermeulen.com/index.php/2017/09/23/using-async-await-in-unity3d-2017/?replytocom=2#respond" onclick="return addComment.moveForm( &quot;div-comment-2&quot;, &quot;2&quot;, &quot;respond&quot;, &quot;53&quot; )" aria-label="Reply to zsaladin" data-slimstat="5">Reply</a></div> </article><!-- .comment-body -->
</li><!-- #comment-## -->
</ol><!-- .comment-list -->
<div id="respond" class="comment-respond">
<h3 id="reply-title" class="comment-reply-title">Leave a Reply <small><a rel="nofollow" id="cancel-comment-reply-link" href="http://www.stevevermeulen.com/index.php/2017/09/23/using-async-await-in-unity3d-2017/#respond" style="display:none;" data-slimstat="5">Cancel reply</a></small></h3> <form action="http://www.stevevermeulen.com/wp-comments-post.php" method="post" id="commentform" class="comment-form" novalidate="">
<p class="comment-notes"><span id="email-notes">Your email address will not be published.</span> Required fields are marked <span class="required">*</span></p><p class="comment-form-comment"><label for="comment">Comment</label> <textarea id="comment" name="comment" cols="45" rows="8" maxlength="65525" aria-required="true" required="required"></textarea></p><p class="comment-form-author"><label for="author">Name <span class="required">*</span></label> <input id="author" name="author" type="text" value="" size="30" maxlength="245" aria-required="true" required="required"></p>
<p class="comment-form-email"><label for="email">Email <span class="required">*</span></label> <input id="email" name="email" type="email" value="" size="30" maxlength="100" aria-describedby="email-notes" aria-required="true" required="required"></p>
<p class="comment-form-url"><label for="url">Website</label> <input id="url" name="url" type="url" value="" size="30" maxlength="200"></p>
<p class="form-submit"><input name="submit" type="submit" id="submit" class="submit" value="Post Comment"> <input type="hidden" name="comment_post_ID" value="53" id="comment_post_ID">
<input type="hidden" name="comment_parent" id="comment_parent" value="0">
</p> </form>
</div><!-- #respond -->
</div><!-- #comments -->
</main><!-- #main -->
</div><!-- #primary -->
</div><!-- #content -->
<footer id="colophon" class="site-footer" role="contentinfo">
<div class="site-info">
<a href="https://wordpress.org/" data-slimstat="5">Proudly powered by WordPress</a>
<span class="sep"> | </span>
Theme: <a href="http://maheshwaghmare.wordpress.com/" rel="designer" data-slimstat="5">Bhari</a> </div><!-- .site-info -->
</footer><!-- #colophon -->
</div><!-- #page -->
<script type="text/javascript" src="./ReadMe_files/shCore.js.download"></script>
<script type="text/javascript" src="./ReadMe_files/shBrushCSharp.js.download"></script>
<script type="text/javascript">
(function(){
var corecss = document.createElement('link');
var themecss = document.createElement('link');
var corecssurl = "http://www.stevevermeulen.com/wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/styles/shCore.css?ver=3.0.9b";
if ( corecss.setAttribute ) {
corecss.setAttribute( "rel", "stylesheet" );
corecss.setAttribute( "type", "text/css" );
corecss.setAttribute( "href", corecssurl );
} else {
corecss.rel = "stylesheet";
corecss.href = corecssurl;
}
document.getElementsByTagName("head")[0].insertBefore( corecss, document.getElementById("syntaxhighlighteranchor") );
var themecssurl = "http://www.stevevermeulen.com/wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/styles/shThemeDefault.css?ver=3.0.9b";
if ( themecss.setAttribute ) {
themecss.setAttribute( "rel", "stylesheet" );
themecss.setAttribute( "type", "text/css" );
themecss.setAttribute( "href", themecssurl );
} else {
themecss.rel = "stylesheet";
themecss.href = themecssurl;
}
//document.getElementById("syntaxhighlighteranchor").appendChild(themecss);
document.getElementsByTagName("head")[0].insertBefore( themecss, document.getElementById("syntaxhighlighteranchor") );
})();
SyntaxHighlighter.config.strings.expandSource = '+ expand source';
SyntaxHighlighter.config.strings.help = '?';
SyntaxHighlighter.config.strings.alert = 'SyntaxHighlighter\n\n';
SyntaxHighlighter.config.strings.noBrush = 'Can\'t find brush for: ';
SyntaxHighlighter.config.strings.brushNotHtmlScript = 'Brush wasn\'t configured for html-script option: ';
SyntaxHighlighter.defaults['pad-line-numbers'] = false;
SyntaxHighlighter.defaults['toolbar'] = false;
SyntaxHighlighter.all();
</script>
<script type="text/javascript" src="./ReadMe_files/comment-reply.min.js.download"></script>
<script type="text/javascript" src="./ReadMe_files/style.min.js.download"></script>
<script type="text/javascript">
/* <![CDATA[ */
var SlimStatParams = {"ajaxurl":"http:\/\/www.stevevermeulen.com\/wp-admin\/admin-ajax.php","extensions_to_track":"pdf,doc,xls,zip","outbound_classes_rel_href_to_not_track":"noslimstat,ab-item","ci":"YTo0OntzOjEyOiJjb250ZW50X3R5cGUiO3M6NDoicG9zdCI7czo4OiJjYXRlZ29yeSI7czozNDoiMyw1LDcsNiw4LDExLDksMTMsMTYsMTIsMTUsMTQsMTAsNCI7czoxMDoiY29udGVudF9pZCI7aTo1MztzOjY6ImF1dGhvciI7czoxMDoic3Zlcm1ldWxlbiI7fQ==.649349fe45a58d0340e865bf413679d9"};
/* ]]> */
</script>
<script type="text/javascript" src="./ReadMe_files/wp-slimstat.min.js.download"></script>
<script type="text/javascript" src="./ReadMe_files/wp-embed.min.js.download"></script>
</body><div id="cVim-status-bar" style="bottom: 0px;"></div><iframe src="./ReadMe_files/cmdline_frame.html" id="cVim-command-frame"></iframe></html>