blob: 51d0da3a59efe3d1341af9d49b4aeec5fe014aef [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="Performance characteristics."><meta name="keywords" content="rust, rustlang, rust-lang, performance"><title>arc_swap::docs::performance - 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="../../../arc_swap/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="../../../arc_swap/index.html"><div class="logo-container"><img class="rust-logo" src="../../../rust-logo.svg" alt="logo"></div></a><h2 class="location"><a href="#">Module performance</a></h2><div class="sidebar-elems"></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">arc_swap</a>::<wbr><a href="../index.html">docs</a>::<wbr><a class="mod" href="#">performance</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/arc_swap/docs/performance.rs.html#1-87">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>Performance characteristics.</p>
<p>There are several performance advantages of <a href="../../type.ArcSwap.html"><code>ArcSwap</code></a> over <a href="std::sync::RwLock"><code>RwLock</code></a>.</p>
<h3 id="lock-free-readers"><a href="#lock-free-readers">Lock-free readers</a></h3>
<p>All the read operations are always <a href="https://en.wikipedia.org/wiki/Non-blocking_algorithm#Lock-freedom">lock-free</a>. Most of the time, they are actually
<a href="https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom">wait-free</a>. They are <a href="https://en.wikipedia.org/wiki/Non-blocking_algorithm#Lock-freedom">lock-free</a> from time to time, with at least <code>usize::MAX / 4</code> accesses
that are <a href="https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom">wait-free</a> in between.</p>
<p>Writers are <a href="https://en.wikipedia.org/wiki/Non-blocking_algorithm#Lock-freedom">lock-free</a>.</p>
<p>Whenever the documentation talks about <em>contention</em> in the context of <a href="../../type.ArcSwap.html"><code>ArcSwap</code></a>, it talks
about contention on the CPU level ‒ multiple cores having to deal with accessing the same cache
line. This slows things down (compared to each one accessing its own cache line), but an
eventual progress is still guaranteed and the cost is significantly lower than parking threads
as with mutex-style contention.</p>
<h3 id="speeds"><a href="#speeds">Speeds</a></h3>
<p>The base line speed of read operations is similar to using an <em>uncontended</em> <a href="std::sync::Mutex"><code>Mutex</code></a>.
However, <a href="../../struct.ArcSwapAny.html#method.load"><code>load</code></a> suffers no contention from any other read operations and only slight
ones during updates. The <a href="../../struct.ArcSwapAny.html#method.load_full"><code>load_full</code></a> operation is additionally contended only on
the reference count of the <a href="std::sync::Arc"><code>Arc</code></a> inside ‒ so, in general, while <a href="std::sync::Mutex"><code>Mutex</code></a> rapidly
loses its performance when being in active use by multiple threads at once and
<a href="std::sync::RwLock"><code>RwLock</code></a> is slow to start with, <a href="../../type.ArcSwap.html"><code>ArcSwap</code></a> mostly keeps its performance even when read by
many threads in parallel.</p>
<p>Write operations are considered expensive. A write operation is more expensive than access to
an <em>uncontended</em> <a href="std::sync::Mutex"><code>Mutex</code></a> and on some architectures even slower than uncontended
<a href="std::sync::RwLock"><code>RwLock</code></a>. However, it is faster than either under contention.</p>
<p>There are some (very unscientific) <a href="https://github.com/vorner/arc-swap/tree/master/benchmarks">benchmarks</a> within the source code of the library, and the
<a href="../../strategy/type.DefaultStrategy.html" title="crate::DefaultStrategy"><code>DefaultStrategy</code></a> has some numbers measured on my computer.</p>
<p>The exact numbers are highly dependant on the machine used (both absolute numbers and relative
between different data structures). Not only architectures have a huge impact (eg. x86 vs ARM),
but even AMD vs. Intel or two different Intel processors. Therefore, if what matters is more
the speed than the wait-free guarantees, you’re advised to do your own measurements.</p>
<p>Further speed improvements may be gained by the use of the <a href="../../cache/struct.Cache.html"><code>Cache</code></a>.</p>
<h3 id="consistency"><a href="#consistency">Consistency</a></h3>
<p>The combination of <a href="https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom">wait-free</a> guarantees of readers and no contention between concurrent
<a href="../../struct.ArcSwapAny.html#method.load"><code>load</code></a>s provides <em>consistent</em> performance characteristics of the synchronization mechanism.
This might be important for soft-realtime applications (the CPU-level contention caused by a
recent update/write operation might be problematic for some hard-realtime cases, though).</p>
<h3 id="choosing-the-right-reading-operation"><a href="#choosing-the-right-reading-operation">Choosing the right reading operation</a></h3>
<p>There are several load operations available. While the general go-to one should be
<a href="../../struct.ArcSwapAny.html#method.load"><code>load</code></a>, there may be situations in which the others are a better match.</p>
<p>The <a href="../../struct.ArcSwapAny.html#method.load"><code>load</code></a> usually only borrows the instance from the shared <a href="../../type.ArcSwap.html"><code>ArcSwap</code></a>. This makes
it faster, because different threads don’t contend on the reference count. There are two
situations when this borrow isn’t possible. If the content gets changed, all existing
<a href="../../struct.Guard.html"><code>Guard</code></a>s are promoted to contain an owned instance. The promotion is done by the
writer, but the readers still need to decrement the reference counts of the old instance when
they no longer use it, contending on the count.</p>
<p>The other situation derives from internal implementation. The number of borrows each thread can
have at each time (across all <a href="../../struct.Guard.html"><code>Guard</code></a>s) is limited. If this limit is exceeded, an owned
instance is created instead.</p>
<p>Therefore, if you intend to hold onto the loaded value for extended time span, you may prefer
<a href="../../struct.ArcSwapAny.html#method.load_full"><code>load_full</code></a>. It loads the pointer instance (<a href="std::sync::Arc"><code>Arc</code></a>) without borrowing, which is
slower (because of the possible contention on the reference count), but doesn’t consume one of
the borrow slots, which will make it more likely for following <a href="../../struct.ArcSwapAny.html#method.load"><code>load</code></a>s to have a slot
available. Similarly, if some API needs an owned <code>Arc</code>, <a href="../../struct.ArcSwapAny.html#method.load_full"><code>load_full</code></a> is more convenient and
potentially faster then first <a href="../../struct.ArcSwapAny.html#method.load"><code>load</code></a>ing and then cloning that <a href="std::sync::Arc"><code>Arc</code></a>.</p>
<p>Additionally, it is possible to use a <a href="../../cache/struct.Cache.html"><code>Cache</code></a> to get further speed improvement at the
cost of less comfortable API and possibly keeping the older values alive for longer than
necessary.</p>
</div></details></section></div></main><div id="rustdoc-vars" data-root-path="../../../" data-current-crate="arc_swap" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.66.0-nightly (5c8bff74b 2022-10-21)" ></div></body></html>