
{"id":172225,"date":"2026-05-29T06:16:01","date_gmt":"2026-05-29T06:16:01","guid":{"rendered":"https:\/\/mycryptomania.com\/?p=172225"},"modified":"2026-05-29T06:16:01","modified_gmt":"2026-05-29T06:16:01","slug":"the-tokio-runtime-for-rust-part-i-websocket","status":"publish","type":"post","link":"https:\/\/mycryptomania.com\/?p=172225","title":{"rendered":"The Tokio Runtime For Rust: Part I, WebSocket."},"content":{"rendered":"<p>Photo by <a href=\"https:\/\/unsplash.com\/@foxre?utm_source=medium&amp;utm_medium=referral\">Jeremy Foster<\/a> on\u00a0<a href=\"https:\/\/unsplash.com\/?utm_source=medium&amp;utm_medium=referral\">Unsplash<\/a><\/p>\n<p>In our previous publication entitled <a href=\"https:\/\/medium.com\/coinmonks\/2026-the-tipping-point-for-rust-in-crypto-trading-a97340a1db3e\">\u201c2026: The Tipping Point for Rust in Crypto Trading\u201d<\/a>, we introduced the official launch of a handcrafted crypto trading connectivity library <a href=\"https:\/\/github.com\/the-ccrs\/ccrs\">CCRS<\/a> which is super simple to use and offers unified API across different exchanges. One of the critical techniques that CCRS employs is the <a href=\"https:\/\/github.com\/tokio-rs\/tokio\">tokio runtime<\/a> for Rust. Since this machinary is so important and sits in the center of our library\u2019s networking layer, we will write several articles about it and spend some time to deep dive into various aspects of the tokio runtime. In particular we will focus our discussions on latency related issues. And for today\u2019s article, let us talk about tokio runtime\u2019s application in and implication to the WebSocket API. We will also use <a href=\"https:\/\/www.bybit.com\/invite?ref=XNYP2K\">Bybit\u2019s<\/a> market data WebSocket API to present concrete examples and gists so that the reader can readily get their hands dirty and learn something by directly \u201ctouching it\u201d.<\/p>\n<p>Our goal is to code a WebSocket client from scratch that listens to the top-of-book market data of Bybit\u2019s spot instrument BTCUSDT in the most performant way. Crypto market is notorious for its extreme volatility and this kind of coding \u201cexercise\u201d is highly relevant in the context of high frequency trading: it is exactly when market conditions become highly volatile when low latency is most needed. For any programming language, in general there are two styles to code a WebSocket client: the blocking style (a.k.a synchronous style) and the non-blocking style (a.k.a asynchronous style).<\/p>\n<p>In the <strong><em>blocking<\/em><\/strong> programming model, each operation waits until it finishes and the current thread is blocked while reading\/writing. The logic is purely linear and therefore easier to understand. It is only good for simple tools, scripts, prototypes, and definitely not suitable for building high frequency trading systems. We are very surprised (in fact a bit astonished) to discover that ccxt maintained <a href=\"https:\/\/accounts.maxweb.black\/register?ref=1116718520\">Binance<\/a> API wrapper binance-rs uses the blocking programming model. As a result, each of its WebSocket connections occupies a dedicated thread. This is undesirable because in crypto high frequency trading we establish many WebSocket connections to gain latency edges. When using binance-rs that translates to many threads which mean many context switching (a CPU core changes threads) and many CPU L1\/L2 cache misses (a thread changes CPU\u00a0core).<\/p>\n<p>In the <strong><em>non-blocking<\/em><\/strong> programming model, operations do not wait for completion and the current thread is never stalled while reading\/writing. Instead, I\/O tasks are delegated to an event loop, allowing a small number of threads (or even a single thread) to manage a large number of concurrent connections efficiently. The control flow is more event-driven and asynchronous, which might make the implementation harder to reason about compared to purely linear blocking code. However, this tradeoff is essential for building modern low-latency and high-throughput systems such as crypto high frequency trading infrastructure. With the non-blocking model, thousands of WebSocket connections can be multiplexed over only a handful of threads, dramatically reducing context switching and minimizing CPU L1\/L2 cache invalidation caused by thread migration across CPU cores. This leads to better scalability, lower latency jitter, and more predictable performance under heavy network loads. Our library <a href=\"https:\/\/github.com\/the-ccrs\/ccrs\">CCRS<\/a> employs the non-blocking programming model and it is based on a popular asynchronous runtime in Rust called\u00a0<a href=\"https:\/\/tokio.rs\/\">Tokio<\/a>.<\/p>\n<p>Does it sound challenging to you? Actually it is super easy to get along with the non-blocking programming model. Below is a simple Rust script that demonstrates how to stream top-of-book market data using multiple <a href=\"https:\/\/www.bybit.com\/invite?ref=XNYP2K\">Bybit<\/a> WebSocket connections running on a single\u00a0thread.<\/p>\n<p>#!\/usr\/bin\/env rust-script<br \/>\/\/! &#8220;`cargo<br \/>\/\/! [dependencies]<br \/>\/\/! tokio = { version = &#8220;1&#8221;, features = [&#8220;full&#8221;] }<br \/>\/\/! tokio-tungstenite = { version = &#8220;0.24&#8221;, features = [&#8220;native-tls&#8221;] }<br \/>\/\/! futures-util = &#8220;0.3&#8221;<br \/>\/\/! serde_json = &#8220;1&#8221;<br \/>\/\/! &#8220;`<\/p>\n<p>use futures_util::{SinkExt, StreamExt};<br \/>use tokio::task::LocalSet;<br \/>use tokio_tungstenite::{connect_async, tungstenite::Message};<\/p>\n<p>async fn subscribe(url: &amp;&#8217;static str, id: usize) {<br \/>    let (ws_stream, _) = connect_async(url).await.expect(&#8220;WebSocket handshake failed&#8221;);<br \/>    let (mut write, mut read) = ws_stream.split();<\/p>\n<p>    let sub = serde_json::json!({ &#8220;op&#8221;: &#8220;subscribe&#8221;, &#8220;args&#8221;: [&#8220;orderbook.1.BTCUSDT&#8221;] });<br \/>    write.send(Message::Text(sub.to_string().into())).await.unwrap();<\/p>\n<p>    while let Some(msg) = read.next().await {<br \/>        match msg {<br \/>            Ok(Message::Text(text)) =&gt; println!(&#8220;[conn-{id}] {text}&#8221;),<br \/>            Ok(Message::Close(frame)) =&gt; {<br \/>                eprintln!(&#8220;[conn-{id}] closed: {frame:?}&#8221;);<br \/>                break;<br \/>            }<br \/>            Err(e) =&gt; {<br \/>                eprintln!(&#8220;[conn-{id}] error: {e}&#8221;);<br \/>                break;<br \/>            }<br \/>            _ =&gt; {}<br \/>        }<br \/>    }<br \/>}<\/p>\n<p>#[tokio::main(flavor = &#8220;current_thread&#8221;)]<br \/>async fn main() {<br \/>    let local = LocalSet::new();<br \/>    let url = &#8220;wss:\/\/stream.bybit.com\/v5\/public\/spot&#8221;;<\/p>\n<p>    for id in 1..=5 {<br \/>        local.spawn_local(subscribe(url, id));<br \/>    }<\/p>\n<p>    local.await;<br \/>} <\/p>\n<p>If you have difficulty understanding what is happening inside this script, copy and paste it into ChatGPT and ask it to explain the code to you piece-by-piece. Now we will leave an exercise to the reader of this article: modify the above-shown script so that it establishes 50 WebSocket connections to <a href=\"https:\/\/accounts.maxweb.black\/register?ref=1116718520\">Binance<\/a> instead of <a href=\"https:\/\/www.bybit.com\/invite?ref=XNYP2K\">Bybit<\/a>, then do the same thing using ccxt maintained <a href=\"https:\/\/accounts.maxweb.black\/register?ref=1116718520\">Binance<\/a> API wrapper binance-rs, and compare the performances.<\/p>\n<p>To summarize, in this article we introduced the fundamental idea behind <a href=\"https:\/\/github.com\/tokio-rs\/tokio\">Tokio\u2019s <strong><em>non-blocking<\/em><\/strong> runtime<\/a> and demonstrated how a single thread can efficiently multiplex many WebSocket connections with minimal overhead. While the example shown here is intentionally simple, the underlying concepts form the backbone of modern low-latency trading infrastructure. Our library <a href=\"https:\/\/github.com\/the-ccrs\/ccrs\">CCRS<\/a> is built around exactly these principles: simplicity, performance, and predictable behavior under extreme market conditions. <a href=\"https:\/\/github.com\/the-ccrs\/ccrs\">CCRS<\/a> supports <a href=\"https:\/\/accounts.maxweb.black\/register?ref=1116718520\">Binance<\/a>, <a href=\"https:\/\/bonus.bitget.com\/0V0WA1\">Bitget<\/a>, <a href=\"https:\/\/www.bybit.com\/invite?ref=XNYP2K\">Bybit<\/a>, <a href=\"https:\/\/advanced.coinbase.com\/join\/CKGCX6U\">Coinbase<\/a>, <a href=\"https:\/\/www.gate.com\/signup\/VLUQXVFWAW?ref_type=103\">Gate<\/a>, <a href=\"https:\/\/www.htx.com\/invite\/en-us\/1f?invite_code=rmw7d223\">HTX<\/a>, <a href=\"https:\/\/app.hyperliquid.xyz\/\">Hyperliquid<\/a>, <a href=\"https:\/\/www.okx.com\/join\/47636709\">OKX<\/a>, and many more coming soon.\u00a0\ud83c\udf89<\/p>\n<p><a href=\"https:\/\/medium.com\/coinmonks\/the-tokio-runtime-for-rust-part-i-websocket-bdb4cee57092\">The Tokio Runtime For Rust: Part I, WebSocket.<\/a> was originally published in <a href=\"https:\/\/medium.com\/coinmonks\">Coinmonks<\/a> on Medium, where people are continuing the conversation by highlighting and responding to this story.<\/p>","protected":false},"excerpt":{"rendered":"<p>Photo by Jeremy Foster on\u00a0Unsplash In our previous publication entitled \u201c2026: The Tipping Point for Rust in Crypto Trading\u201d, we introduced the official launch of a handcrafted crypto trading connectivity library CCRS which is super simple to use and offers unified API across different exchanges. One of the critical techniques that CCRS employs is the [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":172226,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-172225","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-interesting"],"_links":{"self":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts\/172225"}],"collection":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=172225"}],"version-history":[{"count":0,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts\/172225\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/media\/172226"}],"wp:attachment":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=172225"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=172225"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=172225"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}