blob: 4cce37b630b994d0c0373db193160286e4efc427 [file] [log] [blame]
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Asynchronous green-threads."><meta name="keywords" content="rust, rustlang, rust-lang, task"><title>tokio::task - Rust</title><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceSerif4-Regular.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../FiraSans-Regular.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../FiraSans-Medium.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceCodePro-Regular.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceSerif4-Bold.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceCodePro-Semibold.ttf.woff2"><link rel="stylesheet" href="../../normalize.css"><link rel="stylesheet" href="../../rustdoc.css" id="mainThemeStyle"><link rel="stylesheet" href="../../ayu.css" disabled><link rel="stylesheet" href="../../dark.css" disabled><link rel="stylesheet" href="../../light.css" id="themeStyle"><script id="default-settings" ></script><script src="../../storage.js"></script><script defer src="../../main.js"></script><noscript><link rel="stylesheet" href="../../noscript.css"></noscript><link rel="alternate icon" type="image/png" href="../../favicon-16x16.png"><link rel="alternate icon" type="image/png" href="../../favicon-32x32.png"><link rel="icon" type="image/svg+xml" href="../../favicon.svg"></head><body class="rustdoc mod"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle">&#9776;</button><a class="sidebar-logo" href="../../tokio/index.html"><div class="logo-container"><img class="rust-logo" src="../../rust-logo.svg" alt="logo"></div></a><h2></h2></nav><nav class="sidebar"><a class="sidebar-logo" href="../../tokio/index.html"><div class="logo-container"><img class="rust-logo" src="../../rust-logo.svg" alt="logo"></div></a><h2 class="location"><a href="#">Module task</a></h2><div class="sidebar-elems"><section><ul class="block"><li><a href="#modules">Modules</a></li><li><a href="#structs">Structs</a></li><li><a href="#functions">Functions</a></li></ul></section></div></nav><main><div class="width-limiter"><nav class="sub"><form class="search-form"><div class="search-container"><span></span><input class="search-input" name="search" autocomplete="off" spellcheck="false" placeholder="Click or press ‘S’ to search, ‘?’ for more options…" type="search"><div id="help-button" title="help" tabindex="-1"><a href="../../help.html">?</a></div><div id="settings-menu" tabindex="-1"><a href="../../settings.html" title="settings"><img width="22" height="22" alt="Change settings" src="../../wheel.svg"></a></div></div></form></nav><section id="main-content" class="content"><div class="main-heading"><h1 class="fqn">Module <a href="../index.html">tokio</a>::<wbr><a class="mod" href="#">task</a><button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"><img src="../../clipboard.svg" width="19" height="18" alt="Copy item path"></button></h1><span class="out-of-band"><a class="srclink" href="../../src/tokio/task/mod.rs.html#1-333">source</a> · <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">[<span class="inner">&#x2212;</span>]</a></span></div><details class="rustdoc-toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Asynchronous green-threads.</p>
<h3 id="what-are-tasks"><a href="#what-are-tasks">What are Tasks?</a></h3>
<p>A <em>task</em> is a light weight, non-blocking unit of execution. A task is similar
to an OS thread, but rather than being managed by the OS scheduler, they are
managed by the <a href="../runtime/index.html">Tokio runtime</a>. Another name for this general pattern is
<a href="https://en.wikipedia.org/wiki/Green_threads">green threads</a>. If you are familiar with <a href="https://tour.golang.org/concurrency/1">Go’s goroutines</a>, <a href="https://kotlinlang.org/docs/reference/coroutines-overview.html">Kotlin’s
coroutines</a>, or <a href="http://erlang.org/doc/getting_started/conc_prog.html#processes">Erlang’s processes</a>, you can think of Tokio’s tasks as
something similar.</p>
<p>Key points about tasks include:</p>
<ul>
<li>
<p>Tasks are <strong>light weight</strong>. Because tasks are scheduled by the Tokio
runtime rather than the operating system, creating new tasks or switching
between tasks does not require a context switch and has fairly low
overhead. Creating, running, and destroying large numbers of tasks is
quite cheap, especially compared to OS threads.</p>
</li>
<li>
<p>Tasks are scheduled <strong>cooperatively</strong>. Most operating systems implement
<em>preemptive multitasking</em>. This is a scheduling technique where the
operating system allows each thread to run for a period of time, and then
<em>preempts</em> it, temporarily pausing that thread and switching to another.
Tasks, on the other hand, implement <em>cooperative multitasking</em>. In
cooperative multitasking, a task is allowed to run until it <em>yields</em>,
indicating to the Tokio runtime’s scheduler that it cannot currently
continue executing. When a task yields, the Tokio runtime switches to
executing the next task.</p>
</li>
<li>
<p>Tasks are <strong>non-blocking</strong>. Typically, when an OS thread performs I/O or
must synchronize with another thread, it <em>blocks</em>, allowing the OS to
schedule another thread. When a task cannot continue executing, it must
yield instead, allowing the Tokio runtime to schedule another task. Tasks
should generally not perform system calls or other operations that could
block a thread, as this would prevent other tasks running on the same
thread from executing as well. Instead, this module provides APIs for
running blocking operations in an asynchronous context.</p>
</li>
</ul>
<h3 id="working-with-tasks"><a href="#working-with-tasks">Working with Tasks</a></h3>
<p>This module provides the following APIs for working with tasks:</p>
<h4 id="spawning"><a href="#spawning">Spawning</a></h4>
<p>Perhaps the most important function in this module is <a href="fn.spawn.html"><code>task::spawn</code></a>. This
function can be thought of as an async equivalent to the standard library’s
<a href="std::thread::spawn"><code>thread::spawn</code></a>. It takes an <code>async</code> block or other
<a href="std::future::Future">future</a>, and creates a new task to run that work concurrently:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tokio::task;
task::spawn(<span class="kw">async </span>{
<span class="comment">// perform some work here...
</span>});</code></pre></div>
<p>Like <a href="std::thread::spawn"><code>std::thread::spawn</code></a>, <code>task::spawn</code> returns a <a href="struct.JoinHandle.html"><code>JoinHandle</code></a> struct.
A <code>JoinHandle</code> is itself a future which may be used to await the output of
the spawned task. For example:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tokio::task;
<span class="kw">let </span>join = task::spawn(<span class="kw">async </span>{
<span class="comment">// ...
</span><span class="string">&quot;hello world!&quot;
</span>});
<span class="comment">// ...
// Await the result of the spawned task.
</span><span class="kw">let </span>result = join.<span class="kw">await</span><span class="question-mark">?</span>;
<span class="macro">assert_eq!</span>(result, <span class="string">&quot;hello world!&quot;</span>);</code></pre></div>
<p>Again, like <code>std::thread</code>’s <a href="std::thread::JoinHandle"><code>JoinHandle</code> type</a>, if the spawned
task panics, awaiting its <code>JoinHandle</code> will return a <a href="struct.JoinError.html"><code>JoinError</code></a>. For
example:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tokio::task;
<span class="kw">let </span>join = task::spawn(<span class="kw">async </span>{
<span class="macro">panic!</span>(<span class="string">&quot;something bad happened!&quot;</span>)
});
<span class="comment">// The returned result indicates that the task failed.
</span><span class="macro">assert!</span>(join.<span class="kw">await</span>.is_err());</code></pre></div>
<p><code>spawn</code>, <code>JoinHandle</code>, and <code>JoinError</code> are present when the “rt”
feature flag is enabled.</p>
<h4 id="blocking-and-yielding"><a href="#blocking-and-yielding">Blocking and Yielding</a></h4>
<p>As we discussed above, code running in asynchronous tasks should not perform
operations that can block. A blocking operation performed in a task running
on a thread that is also running other tasks would block the entire thread,
preventing other tasks from running.</p>
<p>Instead, Tokio provides two APIs for running blocking operations in an
asynchronous context: <a href="fn.spawn_blocking.html"><code>task::spawn_blocking</code></a> and <a href="fn.block_in_place.html"><code>task::block_in_place</code></a>.</p>
<p>Be aware that if you call a non-async method from async code, that non-async
method is still inside the asynchronous context, so you should also avoid
blocking operations there. This includes destructors of objects destroyed in
async code.</p>
<h5 id="spawn_blocking"><a href="#spawn_blocking">spawn_blocking</a></h5>
<p>The <code>task::spawn_blocking</code> function is similar to the <code>task::spawn</code> function
discussed in the previous section, but rather than spawning an
<em>non-blocking</em> future on the Tokio runtime, it instead spawns a
<em>blocking</em> function on a dedicated thread pool for blocking tasks. For
example:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tokio::task;
task::spawn_blocking(|| {
<span class="comment">// do some compute-heavy work or call synchronous code
</span>});</code></pre></div>
<p>Just like <code>task::spawn</code>, <code>task::spawn_blocking</code> returns a <code>JoinHandle</code>
which we can use to await the result of the blocking operation:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">let </span>join = task::spawn_blocking(|| {
<span class="comment">// do some compute-heavy work or call synchronous code
</span><span class="string">&quot;blocking completed&quot;
</span>});
<span class="kw">let </span>result = join.<span class="kw">await</span><span class="question-mark">?</span>;
<span class="macro">assert_eq!</span>(result, <span class="string">&quot;blocking completed&quot;</span>);</code></pre></div>
<h5 id="block_in_place"><a href="#block_in_place">block_in_place</a></h5>
<p>When using the <a href="../runtime/index.html#threaded-scheduler">multi-threaded runtime</a>, the <a href="fn.block_in_place.html"><code>task::block_in_place</code></a>
function is also available. Like <code>task::spawn_blocking</code>, this function
allows running a blocking operation from an asynchronous context. Unlike
<code>spawn_blocking</code>, however, <code>block_in_place</code> works by transitioning the
<em>current</em> worker thread to a blocking thread, moving other tasks running on
that thread to another worker thread. This can improve performance by avoiding
context switches.</p>
<p>For example:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tokio::task;
<span class="kw">let </span>result = task::block_in_place(|| {
<span class="comment">// do some compute-heavy work or call synchronous code
</span><span class="string">&quot;blocking completed&quot;
</span>});
<span class="macro">assert_eq!</span>(result, <span class="string">&quot;blocking completed&quot;</span>);</code></pre></div>
<h5 id="yield_now"><a href="#yield_now">yield_now</a></h5>
<p>In addition, this module provides a <a href="fn.yield_now.html"><code>task::yield_now</code></a> async function
that is analogous to the standard library’s <a href="std::thread::yield_now"><code>thread::yield_now</code></a>. Calling
and <code>await</code>ing this function will cause the current task to yield to the
Tokio runtime’s scheduler, allowing other tasks to be
scheduled. Eventually, the yielding task will be polled again, allowing it
to execute. For example:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tokio::task;
<span class="kw">async </span>{
task::spawn(<span class="kw">async </span>{
<span class="comment">// ...
</span><span class="macro">println!</span>(<span class="string">&quot;spawned task done!&quot;</span>)
});
<span class="comment">// Yield, allowing the newly-spawned task to execute first.
</span>task::yield_now().<span class="kw">await</span>;
<span class="macro">println!</span>(<span class="string">&quot;main task done!&quot;</span>);
}</code></pre></div>
<h4 id="cooperative-scheduling"><a href="#cooperative-scheduling">Cooperative scheduling</a></h4>
<p>A single call to <a href="method@std::future::Future::poll"><code>poll</code></a> on a top-level task may potentially do a lot of
work before it returns <code>Poll::Pending</code>. If a task runs for a long period of
time without yielding back to the executor, it can starve other tasks
waiting on that executor to execute them, or drive underlying resources.
Since Rust does not have a runtime, it is difficult to forcibly preempt a
long-running task. Instead, this module provides an opt-in mechanism for
futures to collaborate with the executor to avoid starvation.</p>
<p>Consider a future like this one:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">async fn </span>drop_all&lt;I: Stream + Unpin&gt;(<span class="kw-2">mut </span>input: I) {
<span class="kw">while let </span><span class="prelude-val">Some</span>(<span class="kw">_</span>) = input.next().<span class="kw">await </span>{}
}</code></pre></div>
<p>It may look harmless, but consider what happens under heavy load if the
input stream is <em>always</em> ready. If we spawn <code>drop_all</code>, the task will never
yield, and will starve other tasks and resources on the same executor.</p>
<p>To account for this, Tokio has explicit yield points in a number of library
functions, which force tasks to return to the executor periodically.</p>
<h5 id="unconstrained"><a href="#unconstrained">unconstrained</a></h5>
<p>If necessary, <a href="fn.unconstrained.html"><code>task::unconstrained</code></a> lets you opt a future out of of Tokio’s cooperative
scheduling. When a future is wrapped with <code>unconstrained</code>, it will never be forced to yield to
Tokio. For example:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tokio::{task, sync::mpsc};
<span class="kw">let </span>fut = <span class="kw">async </span>{
<span class="kw">let </span>(tx, <span class="kw-2">mut </span>rx) = mpsc::unbounded_channel();
<span class="kw">for </span>i <span class="kw">in </span><span class="number">0</span>..<span class="number">1000 </span>{
<span class="kw">let _ </span>= tx.send(());
<span class="comment">// This will always be ready. If coop was in effect, this code would be forced to yield
// periodically. However, if left unconstrained, then this code will never yield.
</span>rx.recv().<span class="kw">await</span>;
}
};
task::unconstrained(fut).<span class="kw">await</span>;</code></pre></div>
</div></details><h2 id="modules" class="small-section-header"><a href="#modules">Modules</a></h2><div class="item-table"><div class="item-row"><div class="item-left module-item"><a class="mod" href="futures/index.html" title="tokio::task::futures mod">futures</a></div><div class="item-right docblock-short">Task-related futures.</div></div></div><h2 id="structs" class="small-section-header"><a href="#structs">Structs</a></h2><div class="item-table"><div class="item-row"><div class="item-left module-item"><a class="struct" href="struct.AbortHandle.html" title="tokio::task::AbortHandle struct">AbortHandle</a></div><div class="item-right docblock-short">An owned permission to abort a spawned task, without awaiting its completion.</div></div><div class="item-row"><div class="item-left module-item"><a class="struct" href="struct.JoinError.html" title="tokio::task::JoinError struct">JoinError</a></div><div class="item-right docblock-short">Task failed to execute to completion.</div></div><div class="item-row"><div class="item-left module-item"><a class="struct" href="struct.JoinHandle.html" title="tokio::task::JoinHandle struct">JoinHandle</a></div><div class="item-right docblock-short">An owned permission to join on a task (await its termination).</div></div><div class="item-row"><div class="item-left module-item"><a class="struct" href="struct.JoinSet.html" title="tokio::task::JoinSet struct">JoinSet</a></div><div class="item-right docblock-short">A collection of tasks spawned on a Tokio runtime.</div></div><div class="item-row"><div class="item-left module-item"><a class="struct" href="struct.LocalEnterGuard.html" title="tokio::task::LocalEnterGuard struct">LocalEnterGuard</a></div><div class="item-right docblock-short">Context guard for LocalSet</div></div><div class="item-row"><div class="item-left module-item"><a class="struct" href="struct.LocalKey.html" title="tokio::task::LocalKey struct">LocalKey</a></div><div class="item-right docblock-short">A key for task-local data.</div></div><div class="item-row"><div class="item-left module-item"><a class="struct" href="struct.LocalSet.html" title="tokio::task::LocalSet struct">LocalSet</a></div><div class="item-right docblock-short">A set of tasks which are executed on the same thread.</div></div><div class="item-row"><div class="item-left module-item"><a class="struct" href="struct.Unconstrained.html" title="tokio::task::Unconstrained struct">Unconstrained</a></div><div class="item-right docblock-short">Future for the <a href="fn.unconstrained.html"><code>unconstrained</code></a> method.</div></div></div><h2 id="functions" class="small-section-header"><a href="#functions">Functions</a></h2><div class="item-table"><div class="item-row"><div class="item-left module-item"><a class="fn" href="fn.block_in_place.html" title="tokio::task::block_in_place fn">block_in_place</a></div><div class="item-right docblock-short">Runs the provided blocking function on the current thread without
blocking the executor.</div></div><div class="item-row"><div class="item-left module-item"><a class="fn" href="fn.spawn.html" title="tokio::task::spawn fn">spawn</a></div><div class="item-right docblock-short">Spawns a new asynchronous task, returning a
<a href="struct.JoinHandle.html"><code>JoinHandle</code></a> for it.</div></div><div class="item-row"><div class="item-left module-item"><a class="fn" href="fn.spawn_blocking.html" title="tokio::task::spawn_blocking fn">spawn_blocking</a></div><div class="item-right docblock-short">Runs the provided closure on a thread where blocking is acceptable.</div></div><div class="item-row"><div class="item-left module-item"><a class="fn" href="fn.spawn_local.html" title="tokio::task::spawn_local fn">spawn_local</a></div><div class="item-right docblock-short">Spawns a <code>!Send</code> future on the current <a href="struct.LocalSet.html"><code>LocalSet</code></a>.</div></div><div class="item-row"><div class="item-left module-item"><a class="fn" href="fn.unconstrained.html" title="tokio::task::unconstrained fn">unconstrained</a></div><div class="item-right docblock-short">Turn off cooperative scheduling for a future. The future will never be forced to yield by
Tokio. Using this exposes your service to starvation if the unconstrained future never yields
otherwise.</div></div><div class="item-row"><div class="item-left module-item"><a class="fn" href="fn.yield_now.html" title="tokio::task::yield_now fn">yield_now</a></div><div class="item-right docblock-short">Yields execution back to the Tokio runtime.</div></div></div></section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="tokio" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.66.0-nightly (5c8bff74b 2022-10-21)" ></div></body></html>