| <!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="Waits on multiple concurrent branches, returning when the first branch completes, cancelling the remaining branches."><meta name="keywords" content="rust, rustlang, rust-lang, select"><title>select in tokio - 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="sidebar-items.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 macro"><!--[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">☰</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><div class="sidebar-elems"><h2><a href="index.html">In tokio</a></h2></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">Macro <a href="index.html">tokio</a>::<wbr><a class="macro" href="#">select</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/macros/select.rs.html#401-623">source</a> · <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">[<span class="inner">−</span>]</a></span></div><div class="item-decl"><div class="example-wrap"><pre class="rust macro"><code><span class="macro">macro_rules! </span>select { |
| (@ { |
| <span class="comment">// The index of the future to poll first (in bias mode), or the RNG |
| // expression to use to pick a future to poll first. |
| </span>start=<span class="macro-nonterminal">$start</span>:expr; |
| |
| <span class="comment">// One `_` for each branch in the `select!` macro. Passing this to |
| // `count!` converts $skip to an integer. |
| </span>( $(<span class="macro-nonterminal">$count</span>:tt)* ) |
| |
| <span class="comment">// Normalized select branches. `( $skip )` is a set of `_` characters. |
| // There is one `_` for each select branch **before** this one. Given |
| // that all input futures are stored in a tuple, $skip is useful for |
| // generating a pattern to reference the future for the current branch. |
| // $skip is also used as an argument to `count!`, returning the index of |
| // the current select branch. |
| </span>$( ( $(<span class="macro-nonterminal">$skip</span>:tt)* ) <span class="macro-nonterminal">$bind</span>:pat = <span class="macro-nonterminal">$fut</span>:expr, <span class="kw">if </span><span class="macro-nonterminal">$c</span>:expr => <span class="macro-nonterminal">$handle</span>:expr, )+ |
| |
| <span class="comment">// Fallback expression used when all select branches have been disabled. |
| </span>; <span class="macro-nonterminal">$</span><span class="kw">else</span>:<span class="macro-nonterminal">expr |
| |
| </span>}) => { ... }; |
| (@ { start=<span class="macro-nonterminal">$start</span>:expr; $(<span class="macro-nonterminal">$t</span>:tt)* } ) => { ... }; |
| (@ { start=<span class="macro-nonterminal">$start</span>:expr; $(<span class="macro-nonterminal">$t</span>:tt)* } <span class="kw">else </span>=> <span class="macro-nonterminal">$</span><span class="kw">else</span>:<span class="macro-nonterminal">expr </span>$(,)<span class="question-mark">?</span>) => { ... }; |
| (@ { start=<span class="macro-nonterminal">$start</span>:expr; ( $(<span class="macro-nonterminal">$s</span>:tt)* ) $(<span class="macro-nonterminal">$t</span>:tt)* } <span class="macro-nonterminal">$p</span>:pat = <span class="macro-nonterminal">$f</span>:expr, <span class="kw">if </span><span class="macro-nonterminal">$c</span>:expr => <span class="macro-nonterminal">$h</span>:block, $(<span class="macro-nonterminal">$r</span>:tt)* ) => { ... }; |
| (@ { start=<span class="macro-nonterminal">$start</span>:expr; ( $(<span class="macro-nonterminal">$s</span>:tt)* ) $(<span class="macro-nonterminal">$t</span>:tt)* } <span class="macro-nonterminal">$p</span>:pat = <span class="macro-nonterminal">$f</span>:expr => <span class="macro-nonterminal">$h</span>:block, $(<span class="macro-nonterminal">$r</span>:tt)* ) => { ... }; |
| (@ { start=<span class="macro-nonterminal">$start</span>:expr; ( $(<span class="macro-nonterminal">$s</span>:tt)* ) $(<span class="macro-nonterminal">$t</span>:tt)* } <span class="macro-nonterminal">$p</span>:pat = <span class="macro-nonterminal">$f</span>:expr, <span class="kw">if </span><span class="macro-nonterminal">$c</span>:expr => <span class="macro-nonterminal">$h</span>:block $(<span class="macro-nonterminal">$r</span>:tt)* ) => { ... }; |
| (@ { start=<span class="macro-nonterminal">$start</span>:expr; ( $(<span class="macro-nonterminal">$s</span>:tt)* ) $(<span class="macro-nonterminal">$t</span>:tt)* } <span class="macro-nonterminal">$p</span>:pat = <span class="macro-nonterminal">$f</span>:expr => <span class="macro-nonterminal">$h</span>:block $(<span class="macro-nonterminal">$r</span>:tt)* ) => { ... }; |
| (@ { start=<span class="macro-nonterminal">$start</span>:expr; ( $(<span class="macro-nonterminal">$s</span>:tt)* ) $(<span class="macro-nonterminal">$t</span>:tt)* } <span class="macro-nonterminal">$p</span>:pat = <span class="macro-nonterminal">$f</span>:expr, <span class="kw">if </span><span class="macro-nonterminal">$c</span>:expr => <span class="macro-nonterminal">$h</span>:expr ) => { ... }; |
| (@ { start=<span class="macro-nonterminal">$start</span>:expr; ( $(<span class="macro-nonterminal">$s</span>:tt)* ) $(<span class="macro-nonterminal">$t</span>:tt)* } <span class="macro-nonterminal">$p</span>:pat = <span class="macro-nonterminal">$f</span>:expr => <span class="macro-nonterminal">$h</span>:expr ) => { ... }; |
| (@ { start=<span class="macro-nonterminal">$start</span>:expr; ( $(<span class="macro-nonterminal">$s</span>:tt)* ) $(<span class="macro-nonterminal">$t</span>:tt)* } <span class="macro-nonterminal">$p</span>:pat = <span class="macro-nonterminal">$f</span>:expr, <span class="kw">if </span><span class="macro-nonterminal">$c</span>:expr => <span class="macro-nonterminal">$h</span>:expr, $(<span class="macro-nonterminal">$r</span>:tt)* ) => { ... }; |
| (@ { start=<span class="macro-nonterminal">$start</span>:expr; ( $(<span class="macro-nonterminal">$s</span>:tt)* ) $(<span class="macro-nonterminal">$t</span>:tt)* } <span class="macro-nonterminal">$p</span>:pat = <span class="macro-nonterminal">$f</span>:expr => <span class="macro-nonterminal">$h</span>:expr, $(<span class="macro-nonterminal">$r</span>:tt)* ) => { ... }; |
| (biased; <span class="macro-nonterminal">$p</span>:pat = $(<span class="macro-nonterminal">$t</span>:tt)* ) => { ... }; |
| ( <span class="macro-nonterminal">$p</span>:pat = $(<span class="macro-nonterminal">$t</span>:tt)* ) => { ... }; |
| () => { ... }; |
| }</code></pre></div> |
| </div><details class="rustdoc-toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Waits on multiple concurrent branches, returning when the <strong>first</strong> branch |
| completes, cancelling the remaining branches.</p> |
| <p>The <code>select!</code> macro must be used inside of async functions, closures, and |
| blocks.</p> |
| <p>The <code>select!</code> macro accepts one or more branches with the following pattern:</p> |
| <div class="example-wrap"><pre class="language-text"><code><pattern> = <async expression> (, if <precondition>)? => <handler>,</code></pre></div> |
| <p>Additionally, the <code>select!</code> macro may include a single, optional <code>else</code> |
| branch, which evaluates if none of the other branches match their patterns:</p> |
| <div class="example-wrap"><pre class="language-text"><code>else => <expression></code></pre></div> |
| <p>The macro aggregates all <code><async expression></code> expressions and runs them |
| concurrently on the <strong>current</strong> task. Once the <strong>first</strong> expression |
| completes with a value that matches its <code><pattern></code>, the <code>select!</code> macro |
| returns the result of evaluating the completed branch’s <code><handler></code> |
| expression.</p> |
| <p>Additionally, each branch may include an optional <code>if</code> precondition. If the |
| precondition returns <code>false</code>, then the branch is disabled. The provided |
| <code><async expression></code> is still evaluated but the resulting future is never |
| polled. This capability is useful when using <code>select!</code> within a loop.</p> |
| <p>The complete lifecycle of a <code>select!</code> expression is as follows:</p> |
| <ol> |
| <li>Evaluate all provided <code><precondition></code> expressions. If the precondition |
| returns <code>false</code>, disable the branch for the remainder of the current call |
| to <code>select!</code>. Re-entering <code>select!</code> due to a loop clears the “disabled” |
| state.</li> |
| <li>Aggregate the <code><async expression></code>s from each branch, including the |
| disabled ones. If the branch is disabled, <code><async expression></code> is still |
| evaluated, but the resulting future is not polled.</li> |
| <li>Concurrently await on the results for all remaining <code><async expression></code>s.</li> |
| <li>Once an <code><async expression></code> returns a value, attempt to apply the value |
| to the provided <code><pattern></code>, if the pattern matches, evaluate <code><handler></code> |
| and return. If the pattern <strong>does not</strong> match, disable the current branch |
| and for the remainder of the current call to <code>select!</code>. Continue from step 3.</li> |
| <li>If <strong>all</strong> branches are disabled, evaluate the <code>else</code> expression. If no |
| else branch is provided, panic.</li> |
| </ol> |
| <h2 id="runtime-characteristics"><a href="#runtime-characteristics">Runtime characteristics</a></h2> |
| <p>By running all async expressions on the current task, the expressions are |
| able to run <strong>concurrently</strong> but not in <strong>parallel</strong>. This means all |
| expressions are run on the same thread and if one branch blocks the thread, |
| all other expressions will be unable to continue. If parallelism is |
| required, spawn each async expression using <a href="task/fn.spawn.html"><code>tokio::spawn</code></a> and pass the |
| join handle to <code>select!</code>.</p> |
| <h2 id="fairness"><a href="#fairness">Fairness</a></h2> |
| <p>By default, <code>select!</code> randomly picks a branch to check first. This provides |
| some level of fairness when calling <code>select!</code> in a loop with branches that |
| are always ready.</p> |
| <p>This behavior can be overridden by adding <code>biased;</code> to the beginning of the |
| macro usage. See the examples for details. This will cause <code>select</code> to poll |
| the futures in the order they appear from top to bottom. There are a few |
| reasons you may want this:</p> |
| <ul> |
| <li>The random number generation of <code>tokio::select!</code> has a non-zero CPU cost</li> |
| <li>Your futures may interact in a way where known polling order is significant</li> |
| </ul> |
| <p>But there is an important caveat to this mode. It becomes your responsibility |
| to ensure that the polling order of your futures is fair. If for example you |
| are selecting between a stream and a shutdown future, and the stream has a |
| huge volume of messages and zero or nearly zero time between them, you should |
| place the shutdown future earlier in the <code>select!</code> list to ensure that it is |
| always polled, and will not be ignored due to the stream being constantly |
| ready.</p> |
| <h2 id="panics"><a href="#panics">Panics</a></h2> |
| <p>The <code>select!</code> macro panics if all branches are disabled <strong>and</strong> there is no |
| provided <code>else</code> branch. A branch is disabled when the provided <code>if</code> |
| precondition returns <code>false</code> <strong>or</strong> when the pattern does not match the |
| result of <code><async expression></code>.</p> |
| <h2 id="cancellation-safety"><a href="#cancellation-safety">Cancellation safety</a></h2> |
| <p>When using <code>select!</code> in a loop to receive messages from multiple sources, |
| you should make sure that the receive call is cancellation safe to avoid |
| losing messages. This section goes through various common methods and |
| describes whether they are cancel safe. The lists in this section are not |
| exhaustive.</p> |
| <p>The following methods are cancellation safe:</p> |
| <ul> |
| <li><a href="sync/mpsc/struct.Receiver.html#method.recv"><code>tokio::sync::mpsc::Receiver::recv</code></a></li> |
| <li><a href="sync/mpsc/struct.UnboundedReceiver.html#method.recv"><code>tokio::sync::mpsc::UnboundedReceiver::recv</code></a></li> |
| <li><a href="sync/broadcast/struct.Receiver.html#method.recv"><code>tokio::sync::broadcast::Receiver::recv</code></a></li> |
| <li><a href="sync/watch/struct.Receiver.html#method.changed"><code>tokio::sync::watch::Receiver::changed</code></a></li> |
| <li><a href="net/struct.TcpListener.html#method.accept"><code>tokio::net::TcpListener::accept</code></a></li> |
| <li><a href="net/struct.UnixListener.html#method.accept"><code>tokio::net::UnixListener::accept</code></a></li> |
| <li><a href="crate::signal::unix::Signal::recv"><code>tokio::signal::unix::Signal::recv</code></a></li> |
| <li><a href="io/trait.AsyncReadExt.html#method.read"><code>tokio::io::AsyncReadExt::read</code></a> on any <code>AsyncRead</code></li> |
| <li><a href="io/trait.AsyncReadExt.html#method.read_buf"><code>tokio::io::AsyncReadExt::read_buf</code></a> on any <code>AsyncRead</code></li> |
| <li><a href="io/trait.AsyncWriteExt.html#method.write"><code>tokio::io::AsyncWriteExt::write</code></a> on any <code>AsyncWrite</code></li> |
| <li><a href="io/trait.AsyncWriteExt.html#method.write_buf"><code>tokio::io::AsyncWriteExt::write_buf</code></a> on any <code>AsyncWrite</code></li> |
| <li><a href="https://docs.rs/tokio-stream/0.1/tokio_stream/trait.StreamExt.html#method.next"><code>tokio_stream::StreamExt::next</code></a> on any <code>Stream</code></li> |
| <li><a href="https://docs.rs/futures/0.3/futures/stream/trait.StreamExt.html#method.next"><code>futures::stream::StreamExt::next</code></a> on any <code>Stream</code></li> |
| </ul> |
| <p>The following methods are not cancellation safe and can lead to loss of data:</p> |
| <ul> |
| <li><a href="io/trait.AsyncReadExt.html#method.read_exact"><code>tokio::io::AsyncReadExt::read_exact</code></a></li> |
| <li><a href="io/trait.AsyncReadExt.html#method.read_to_end"><code>tokio::io::AsyncReadExt::read_to_end</code></a></li> |
| <li><a href="io/trait.AsyncReadExt.html#method.read_to_string"><code>tokio::io::AsyncReadExt::read_to_string</code></a></li> |
| <li><a href="io/trait.AsyncWriteExt.html#method.write_all"><code>tokio::io::AsyncWriteExt::write_all</code></a></li> |
| </ul> |
| <p>The following methods are not cancellation safe because they use a queue for |
| fairness and cancellation makes you lose your place in the queue:</p> |
| <ul> |
| <li><a href="sync/struct.Mutex.html#method.lock"><code>tokio::sync::Mutex::lock</code></a></li> |
| <li><a href="sync/struct.RwLock.html#method.read"><code>tokio::sync::RwLock::read</code></a></li> |
| <li><a href="sync/struct.RwLock.html#method.write"><code>tokio::sync::RwLock::write</code></a></li> |
| <li><a href="sync/struct.Semaphore.html#method.acquire"><code>tokio::sync::Semaphore::acquire</code></a></li> |
| <li><a href="sync/struct.Notify.html#method.notified"><code>tokio::sync::Notify::notified</code></a></li> |
| </ul> |
| <p>To determine whether your own methods are cancellation safe, look for the |
| location of uses of <code>.await</code>. This is because when an asynchronous method is |
| cancelled, that always happens at an <code>.await</code>. If your function behaves |
| correctly even if it is restarted while waiting at an <code>.await</code>, then it is |
| cancellation safe.</p> |
| <p>Cancellation safety can be defined in the following way: If you have a |
| future that has not yet completed, then it must be a no-op to drop that |
| future and recreate it. This definition is motivated by the situation where |
| a <code>select!</code> is used in a loop. Without this guarantee, you would lose your |
| progress when another branch completes and you restart the <code>select!</code> by |
| going around the loop.</p> |
| <p>Be aware that cancelling something that is not cancellation safe is not |
| necessarily wrong. For example, if you are cancelling a task because the |
| application is shutting down, then you probably don’t care that partially |
| read data is lost.</p> |
| <h2 id="examples"><a href="#examples">Examples</a></h2> |
| <p>Basic select with two branches.</p> |
| |
| <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">async fn </span>do_stuff_async() { |
| <span class="comment">// async work |
| </span>} |
| |
| <span class="kw">async fn </span>more_async_work() { |
| <span class="comment">// more here |
| </span>} |
| |
| <span class="attribute">#[tokio::main] |
| </span><span class="kw">async fn </span>main() { |
| <span class="macro">tokio::select! </span>{ |
| <span class="kw">_ </span>= do_stuff_async() => { |
| <span class="macro">println!</span>(<span class="string">"do_stuff_async() completed first"</span>) |
| } |
| <span class="kw">_ </span>= more_async_work() => { |
| <span class="macro">println!</span>(<span class="string">"more_async_work() completed first"</span>) |
| } |
| }; |
| }</code></pre></div> |
| <p>Basic stream selecting.</p> |
| |
| <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tokio_stream::{<span class="self">self </span><span class="kw">as </span>stream, StreamExt}; |
| |
| <span class="attribute">#[tokio::main] |
| </span><span class="kw">async fn </span>main() { |
| <span class="kw">let </span><span class="kw-2">mut </span>stream1 = stream::iter(<span class="macro">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]); |
| <span class="kw">let </span><span class="kw-2">mut </span>stream2 = stream::iter(<span class="macro">vec!</span>[<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>]); |
| |
| <span class="kw">let </span>next = <span class="macro">tokio::select! </span>{ |
| v = stream1.next() => v.unwrap(), |
| v = stream2.next() => v.unwrap(), |
| }; |
| |
| <span class="macro">assert!</span>(next == <span class="number">1 </span>|| next == <span class="number">4</span>); |
| }</code></pre></div> |
| <p>Collect the contents of two streams. In this example, we rely on pattern |
| matching and the fact that <code>stream::iter</code> is “fused”, i.e. once the stream |
| is complete, all calls to <code>next()</code> return <code>None</code>.</p> |
| |
| <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tokio_stream::{<span class="self">self </span><span class="kw">as </span>stream, StreamExt}; |
| |
| <span class="attribute">#[tokio::main] |
| </span><span class="kw">async fn </span>main() { |
| <span class="kw">let </span><span class="kw-2">mut </span>stream1 = stream::iter(<span class="macro">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]); |
| <span class="kw">let </span><span class="kw-2">mut </span>stream2 = stream::iter(<span class="macro">vec!</span>[<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>]); |
| |
| <span class="kw">let </span><span class="kw-2">mut </span>values = <span class="macro">vec!</span>[]; |
| |
| <span class="kw">loop </span>{ |
| <span class="macro">tokio::select! </span>{ |
| <span class="prelude-val">Some</span>(v) = stream1.next() => values.push(v), |
| <span class="prelude-val">Some</span>(v) = stream2.next() => values.push(v), |
| <span class="kw">else </span>=> <span class="kw">break</span>, |
| } |
| } |
| |
| values.sort(); |
| <span class="macro">assert_eq!</span>(<span class="kw-2">&</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>], <span class="kw-2">&</span>values[..]); |
| }</code></pre></div> |
| <p>Using the same future in multiple <code>select!</code> expressions can be done by passing |
| a reference to the future. Doing so requires the future to be <a href="https://doc.rust-lang.org/nightly/core/marker/trait.Unpin.html"><code>Unpin</code></a>. A |
| future can be made <a href="https://doc.rust-lang.org/nightly/core/marker/trait.Unpin.html"><code>Unpin</code></a> by either using <a href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html#method.pin"><code>Box::pin</code></a> or stack pinning.</p> |
| <p>Here, a stream is consumed for at most 1 second.</p> |
| |
| <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tokio_stream::{<span class="self">self </span><span class="kw">as </span>stream, StreamExt}; |
| <span class="kw">use </span>tokio::time::{<span class="self">self</span>, Duration}; |
| |
| <span class="attribute">#[tokio::main] |
| </span><span class="kw">async fn </span>main() { |
| <span class="kw">let </span><span class="kw-2">mut </span>stream = stream::iter(<span class="macro">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]); |
| <span class="kw">let </span>sleep = time::sleep(Duration::from_secs(<span class="number">1</span>)); |
| <span class="macro">tokio::pin!</span>(sleep); |
| |
| <span class="kw">loop </span>{ |
| <span class="macro">tokio::select! </span>{ |
| maybe_v = stream.next() => { |
| <span class="kw">if let </span><span class="prelude-val">Some</span>(v) = maybe_v { |
| <span class="macro">println!</span>(<span class="string">"got = {}"</span>, v); |
| } <span class="kw">else </span>{ |
| <span class="kw">break</span>; |
| } |
| } |
| <span class="kw">_ </span>= <span class="kw-2">&mut </span>sleep => { |
| <span class="macro">println!</span>(<span class="string">"timeout"</span>); |
| <span class="kw">break</span>; |
| } |
| } |
| } |
| }</code></pre></div> |
| <p>Joining two values using <code>select!</code>.</p> |
| |
| <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tokio::sync::oneshot; |
| |
| <span class="attribute">#[tokio::main] |
| </span><span class="kw">async fn </span>main() { |
| <span class="kw">let </span>(tx1, <span class="kw-2">mut </span>rx1) = oneshot::channel(); |
| <span class="kw">let </span>(tx2, <span class="kw-2">mut </span>rx2) = oneshot::channel(); |
| |
| tokio::spawn(<span class="kw">async move </span>{ |
| tx1.send(<span class="string">"first"</span>).unwrap(); |
| }); |
| |
| tokio::spawn(<span class="kw">async move </span>{ |
| tx2.send(<span class="string">"second"</span>).unwrap(); |
| }); |
| |
| <span class="kw">let </span><span class="kw-2">mut </span>a = <span class="prelude-val">None</span>; |
| <span class="kw">let </span><span class="kw-2">mut </span>b = <span class="prelude-val">None</span>; |
| |
| <span class="kw">while </span>a.is_none() || b.is_none() { |
| <span class="macro">tokio::select! </span>{ |
| v1 = (<span class="kw-2">&mut </span>rx1), <span class="kw">if </span>a.is_none() => a = <span class="prelude-val">Some</span>(v1.unwrap()), |
| v2 = (<span class="kw-2">&mut </span>rx2), <span class="kw">if </span>b.is_none() => b = <span class="prelude-val">Some</span>(v2.unwrap()), |
| } |
| } |
| |
| <span class="kw">let </span>res = (a.unwrap(), b.unwrap()); |
| |
| <span class="macro">assert_eq!</span>(res.<span class="number">0</span>, <span class="string">"first"</span>); |
| <span class="macro">assert_eq!</span>(res.<span class="number">1</span>, <span class="string">"second"</span>); |
| }</code></pre></div> |
| <p>Using the <code>biased;</code> mode to control polling order.</p> |
| |
| <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="attribute">#[tokio::main] |
| </span><span class="kw">async fn </span>main() { |
| <span class="kw">let </span><span class="kw-2">mut </span>count = <span class="number">0u8</span>; |
| |
| <span class="kw">loop </span>{ |
| <span class="macro">tokio::select! </span>{ |
| <span class="comment">// If you run this example without `biased;`, the polling order is |
| // pseudo-random, and the assertions on the value of count will |
| // (probably) fail. |
| </span>biased; |
| |
| <span class="kw">_ </span>= <span class="kw">async </span>{}, <span class="kw">if </span>count < <span class="number">1 </span>=> { |
| count += <span class="number">1</span>; |
| <span class="macro">assert_eq!</span>(count, <span class="number">1</span>); |
| } |
| <span class="kw">_ </span>= <span class="kw">async </span>{}, <span class="kw">if </span>count < <span class="number">2 </span>=> { |
| count += <span class="number">1</span>; |
| <span class="macro">assert_eq!</span>(count, <span class="number">2</span>); |
| } |
| <span class="kw">_ </span>= <span class="kw">async </span>{}, <span class="kw">if </span>count < <span class="number">3 </span>=> { |
| count += <span class="number">1</span>; |
| <span class="macro">assert_eq!</span>(count, <span class="number">3</span>); |
| } |
| <span class="kw">_ </span>= <span class="kw">async </span>{}, <span class="kw">if </span>count < <span class="number">4 </span>=> { |
| count += <span class="number">1</span>; |
| <span class="macro">assert_eq!</span>(count, <span class="number">4</span>); |
| } |
| |
| <span class="kw">else </span>=> { |
| <span class="kw">break</span>; |
| } |
| }; |
| } |
| }</code></pre></div> |
| <h3 id="avoid-racy-if-preconditions"><a href="#avoid-racy-if-preconditions">Avoid racy <code>if</code> preconditions</a></h3> |
| <p>Given that <code>if</code> preconditions are used to disable <code>select!</code> branches, some |
| caution must be used to avoid missing values.</p> |
| <p>For example, here is <strong>incorrect</strong> usage of <code>sleep</code> with <code>if</code>. The objective |
| is to repeatedly run an asynchronous task for up to 50 milliseconds. |
| However, there is a potential for the <code>sleep</code> completion to be missed.</p> |
| |
| <div class="example-wrap should_panic"><div class='tooltip'>ⓘ</div><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tokio::time::{<span class="self">self</span>, Duration}; |
| |
| <span class="kw">async fn </span>some_async_work() { |
| <span class="comment">// do work |
| </span>} |
| |
| <span class="attribute">#[tokio::main] |
| </span><span class="kw">async fn </span>main() { |
| <span class="kw">let </span>sleep = time::sleep(Duration::from_millis(<span class="number">50</span>)); |
| <span class="macro">tokio::pin!</span>(sleep); |
| |
| <span class="kw">while </span>!sleep.is_elapsed() { |
| <span class="macro">tokio::select! </span>{ |
| <span class="kw">_ </span>= <span class="kw-2">&mut </span>sleep, <span class="kw">if </span>!sleep.is_elapsed() => { |
| <span class="macro">println!</span>(<span class="string">"operation timed out"</span>); |
| } |
| <span class="kw">_ </span>= some_async_work() => { |
| <span class="macro">println!</span>(<span class="string">"operation completed"</span>); |
| } |
| } |
| } |
| |
| <span class="macro">panic!</span>(<span class="string">"This example shows how not to do it!"</span>); |
| }</code></pre></div> |
| <p>In the above example, <code>sleep.is_elapsed()</code> may return <code>true</code> even if |
| <code>sleep.poll()</code> never returned <code>Ready</code>. This opens up a potential race |
| condition where <code>sleep</code> expires between the <code>while !sleep.is_elapsed()</code> |
| check and the call to <code>select!</code> resulting in the <code>some_async_work()</code> call to |
| run uninterrupted despite the sleep having elapsed.</p> |
| <p>One way to write the above example without the race would be:</p> |
| |
| <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tokio::time::{<span class="self">self</span>, Duration}; |
| |
| <span class="kw">async fn </span>some_async_work() { |
| <span class="comment">// do work |
| </span>} |
| |
| <span class="attribute">#[tokio::main] |
| </span><span class="kw">async fn </span>main() { |
| <span class="kw">let </span>sleep = time::sleep(Duration::from_millis(<span class="number">50</span>)); |
| <span class="macro">tokio::pin!</span>(sleep); |
| |
| <span class="kw">loop </span>{ |
| <span class="macro">tokio::select! </span>{ |
| <span class="kw">_ </span>= <span class="kw-2">&mut </span>sleep => { |
| <span class="macro">println!</span>(<span class="string">"operation timed out"</span>); |
| <span class="kw">break</span>; |
| } |
| <span class="kw">_ </span>= some_async_work() => { |
| <span class="macro">println!</span>(<span class="string">"operation completed"</span>); |
| } |
| } |
| } |
| }</code></pre></div> |
| </div></details></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> |