{"id":11615,"date":"2025-08-18T20:13:42","date_gmt":"2025-08-18T20:13:42","guid":{"rendered":"https:\/\/putridparrot.com\/blog\/?p=11615"},"modified":"2025-08-18T20:13:42","modified_gmt":"2025-08-18T20:13:42","slug":"async-await-using-tokio-and-rust","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/async-await-using-tokio-and-rust\/","title":{"rendered":"Async\/await using tokio and Rust"},"content":{"rendered":"<p>Rust supports async\/await in a similar way to C# although these are supplied via runtimes, for example Tokio, async-std and others. <\/p>\n<p>In this post we&#8217;ll look at the tokio runtime option.<\/p>\n<p>The first thing we need to do is add tokio to the Cargo.toml, for example<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&#x5B;dependencies]\r\ntokio = { version = &quot;1&quot;, features = &#x5B;&quot;full&quot;] }\r\n<\/pre>\n<p>Now, let&#8217;s create a simple async function<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nasync fn execute() {\r\n   println!(&quot;Execution in async function&quot;);\r\n}\r\n<\/pre>\n<p>Notice we do not return a Task like C# or any type in this case, but this is essentially syntactic sugar for<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nfn execute() -&gt; impl Future&lt;Output = ()&gt; \r\n<\/pre>\n<p>Hence, we can see async functions return a Future (similar to a Promise in Javascript etc.).<\/p>\n<p>The Future trait has a <em>poll<\/em> function which can be checked to see if the async function is ready to return a value or if it&#8217;s pending.<\/p>\n<p>To await an async function we use te following syntax<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nexecute().await;\r\n<\/pre>\n<p>The await will ofcourse cause the current Future to return to the caller but the code after the await will not execute until the Future completes\/is ready. <\/p>\n<p>If you come from C# this is much the same, i.e. running a continuation when completed etc.<\/p>\n<p>To use asyc\/await on <em>main<\/em> we need to make a couple of changes, first to make main async but this alone will not work without the runtime, hence main looks like this<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n#&#x5B;tokio::main]\r\nasync fn main() {\r\n  execute().await;\r\n}\r\n<\/pre>\n<p>Futures are lazy loaded. Meaning, that the future will not execute until the await is called.<\/p>\n<p>As you can see Futures do not run in a thread, they are just polling futures. However we can use tokio tasks (which looks a lot like std lib threads) the execute the code on a thread<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\"> \r\nlet handle = tokio::spawn(asyc move {\r\n   execute().await;\r\n}\r\n\r\nhandle.await.unwrap();\r\n<\/pre>\n<p>By default tokio executes on a threadpool but we could change things, as below<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n#&#x5B;tokio::main(flavor = &quot;current_thread&quot;)]\r\n<\/pre>\n<p>Which then uses time slicing instead of threads.<\/p>\n<p>Tokio is good for non blocking IO, but tokio uses a single thread for it&#8217;s main event loop hence heavy CPU will basically slow down other tasks. Hence we would need to spawn threads as already discussed.<\/p>\n<p><strong>Slight detour<\/strong><\/p>\n<p>As a slight detour from async\/await &#8211; tokio can also create &#8220;green&#8221; threads (lightweight threads from the runtime &#8211; not OS threads), for example<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nasync fn execute() {\r\n   time::sleep(time::Duration::from_secs(1)).await;\r\n}\r\n\r\nfn main() {\r\n  let runtime = tokio::runtime::Runtime::new().unwrap();\r\n  \r\n  let future = execute();\r\n\r\n  runtime.block_on(future);\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Rust supports async\/await in a similar way to C# although these are supplied via runtimes, for example Tokio, async-std and others. In this post we&#8217;ll look at the tokio runtime option. The first thing we need to do is add tokio to the Cargo.toml, for example &#x5B;dependencies] tokio = { version = &quot;1&quot;, features = [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[191],"tags":[],"class_list":["post-11615","post","type-post","status-publish","format-standard","hentry","category-rust"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11615","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=11615"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11615\/revisions"}],"predecessor-version":[{"id":11653,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11615\/revisions\/11653"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=11615"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=11615"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=11615"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}