Hands-On Concurrency with Rust
Confidently build memory-safe, parallel, and efficient software in Rust
Brian L. Troutwine
- 462 pages
- English
- ePUB (adapté aux mobiles)
- Disponible sur iOS et Android
Hands-On Concurrency with Rust
Confidently build memory-safe, parallel, and efficient software in Rust
Brian L. Troutwine
Ă propos de ce livre
Get to grips with modern software demands by learning the effective uses of Rust's powerful memory safety.About This Bookâą Learn and improve the sequential performance characteristics of your softwareâą Understand the use of operating system processes in a high-scale concurrent systemâą Learn of the various coordination methods available in the Standard libraryWho This Book Is ForThis book is aimed at software engineers with a basic understanding of Rust who want to exploit the parallel and concurrent nature of modern computing environments, safely.What You Will Learnâą Probe your programs for performance and accuracy issuesâą Create your own threading and multi-processing environment in Rustâą Use coarse locks from Rust's Standard libraryâą Solve common synchronization problems or avoid synchronization using atomic programmingâą Build lock-free/wait-free structures in Rust and understand their implementations in the crates ecosystemâą Leverage Rust's memory model and type system to build safety properties into your parallel programsâą Understand the new features of the Rust programming language to ease the writing of parallel programsIn DetailMost programming languages can really complicate things, especially with regard to unsafe memory access. The burden on you, the programmer, lies across two domains: understanding the modern machine and your language's pain-points. This book will teach you to how to manage program performance on modern machines and build fast, memory-safe, and concurrent software in Rust. It starts with the fundamentals of Rust and discusses machine architecture concepts. You will be taken through ways to measure and improve the performance of Rust code systematically and how to write collections with confidence. You will learn about the Sync and Send traits applied to threads, and coordinate thread execution with locks, atomic primitives, data-parallelism, and more.The book will show you how to efficiently embed Rust in C++ code and explore the functionalities of various crates for multithreaded applications. It explores implementations in depth. You will know how a mutex works and build several yourself. You will master radically different approaches that exist in the ecosystem for structuring and managing high-scale systems.By the end of the book, you will feel comfortable with designing safe, consistent, parallel, and high-performance applications in Rust.Style and approachReaders will be taken through various ways to improve the performance of their Rust code.
Foire aux questions
Informations
High-Level Parallelism â Threadpools, Parallel Iterators and Processes
- Explored the implementation of thread pool
- Understood how thread pooling relates to the operation of rayon
- Explored rayon's internal mechanism in-depth
- Demonstrated the use of rayon in a non-trivial exercise
Technical requirements
You can find the source code for this book's projects on GitHub: https://github.com/PacktPublishing/Hands-On-Concurrency-with-Rust. The source code for this chapter is under Chapter08.
Thread pooling
Slowloris â attacking thread-per-connection servers
The server
[package] name = "overwhelmed_tcp_server" version = "0.1.0" authors = ["Brian L. Troutwine <[email protected]>"] [dependencies] clap = "2.31" slog = "2.2" slog-term = "2.4" slog-async = "2.3" [[bin]] name = "server" [[bin]] name = "client"
#[macro_use] extern crate slog; extern crate clap; extern crate slog_async; extern crate slog_term; use clap::{App, Arg}; use slog::Drain; use std::io::{self, BufRead, BufReader, BufWriter, Write}; use std::net::{TcpListener, TcpStream};
use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread; static TOTAL_STREAMS: AtomicUsize = AtomicUsize::new(0);
fn main() { let decorator = slog_term::TermDecorator::new().build(); let drain = slog_term::CompactFormat::new(decorator).build().fuse(); let drain = slog_async::Async::new(drain).build().fuse(); let root = slog::Logger::root(drain, o!());
let matches = App::new("server") .arg( Arg::with_name("host") .long("host") .value_name("HOST") .help("Sets which hostname to listen on") .takes_value(true), ) .arg( Arg::with_name("port") .long("port") .value_name("PORT") .help("Sets which port to listen on") .takes_value(true), ) .get_matches(); let host: &str = matches.value_of("host").unwrap_or("localhost"); let port = matches .value_of("port") .unwrap_or("1987") .parse::<u16>() .expect("port-no not valid");
let listener = TcpListener::bind((host, port)).unwrap();
let server = root.new(o!("host" => host.to_string(),
"port" => port)); info!(server, "Server open for business! :D"); let mut joins = Vec::new(); for stream in listener.incoming() { if let Ok(stream) = stream { let stream_no = TOTAL_STREAMS.fetch_add(1,
Ordering::Relaxed); let log = root.new(o!("stream-no" => stream_no, "peer-addr" => stream.peer_addr()
.expect("no peer address")
.to_string())); let writer = BufWriter::new(
stream.try_clone()
.expect("could not clone stream")); let reader = BufReader::new(stream); match handle_client(log, reader, writer) { Ok(handler) => { joins.push(handler); } Err(err) => { error!(server,
"Could not make client handler. {:?}",
err); } } } else { info!(root, "Shutting down! {:?}", stream); } } info!( server, "No more incoming connections. Draining existing connections." ); for jh in joins { if let Err(err) = jh.join() { info!(server,
"Connection handler died with error: {:?}",
err); } } }
fn handle_client( log: slog::Logger, mut reader: BufReader<TcpStream>, mut writer: BufWriter<TcpStream>, ) -> io::Result<thread::JoinHandle<()>> { let builder = thread::Builder::new(); builder.spawn(move || { let mut buf = String::with_capacity(2048); while let Ok(sz) = reader.read_line(&mut buf) { info!(log, "Received a {} bytes: {}", sz, buf); writer .write_all(&buf.as_bytes()) .expect("could not write line"); buf.clear(); } TOTAL_STREAMS.fetch_sub(1, Ordering::Relaxed); }) }
> cargo run --release --bin server Finished release [optimized] target(s) in 0.26 secs Running `target/release/server` host: localhost port: 1987 Apr 22 21:31:14.001 INFO Server open for business! :D
> telnet localhost 1987 Trying ::1... Connected to localhost. Escape character is '^]'. hello server
stream-no: 0 peer-addr: [::1]:65219 Apr 22 21:32:54.943 INFO Received a 14 bytes: hello server
The client
#[macro_use] extern crate slog; extern crate clap; extern crate slog_async; extern crate slog_term; use clap::{App, Arg}; use slog::Drain; use std::net::TcpStream; use std::sync::atomic::{AtomicUsize, Ordering}; use std::{thread, time}; static TOTAL_STREAMS: AtomicUsize = AtomicUsize::new(0);
fn report(log: slog::Logger) { let delay = time::Duration::from_millis(1000); let mut total_streams = 0; loop { let streams_per_second = TOTAL_STREAMS.swap(0, Ordering::Relaxed); info!(log, "Total connections: {}", total_streams); info!(log, "Connections per second: {}", streams_per_second); total_streams += streams_per_second; thread::sleep(delay); } }