├── .gitignore ├── t ├── Cargo.toml ├── main.go ├── Readme.md ├── main.rs └── main-affinity.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /t: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | command time --format 'real %es\nuser %Us\nsys %Ss\nrss %Mk' "$@" 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "affinity" 3 | version = "0.1.0" 4 | authors = ["Aleksey Kladov "] 5 | edition = "2018" 6 | 7 | [[bin]] 8 | name = "main" 9 | path = "main-affinity.rs" 10 | 11 | [dependencies] 12 | core_affinity = "=0.5.10" 13 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | var wg sync.WaitGroup 10 | for i := uint32(0); i < 10_000; i++ { 11 | i := i 12 | wg.Add(1) 13 | go func() { 14 | defer wg.Done() 15 | bad_hash := (i * 2654435761) % 200_000 16 | time.Sleep(time.Duration(bad_hash) * time.Microsecond) 17 | for j := 0; j < 1000; j++ { 18 | time.Sleep(10 * time.Millisecond) 19 | } 20 | }() 21 | } 22 | wg.Wait() 23 | } 24 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | Creating 10_000 threads on Linux 2 | 3 | ``` 4 | λ rustc main.rs -C opt-level=3 && ./t ./main 5 | real 10.35s 6 | user 5.14s 7 | sys 16.04s 8 | rss 94628k 9 | 10 | λ go build main.go && ./t ./main 11 | real 10.92s 12 | user 13.00s 13 | sys 0.50s 14 | rss 34612k 15 | 16 | λ cargo build -q --release && ./t ./target/release/main --pin-to-core 17 | real 10.35s 18 | user 3.00s 19 | sys 8.94s 20 | rss 94916k 21 | ``` 22 | 23 | See [this post](https://matklad.github.io/2021/03/12/goroutines-are-not-significantly-lighter-than-threads.html) for discussion. 24 | -------------------------------------------------------------------------------- /main.rs: -------------------------------------------------------------------------------- 1 | use std::{thread, time::Duration}; 2 | 3 | fn main() { 4 | let mut threads = Vec::new(); 5 | for i in 0..10_000u32 { 6 | let t = thread::spawn(move || { 7 | let bad_hash = i.wrapping_mul(2654435761) % 200_000; 8 | thread::sleep(Duration::from_micros(bad_hash as u64)); 9 | for _ in 0..1000 { 10 | thread::sleep(Duration::from_millis(10)); 11 | } 12 | }); 13 | threads.push(t); 14 | } 15 | 16 | for t in threads { 17 | t.join().unwrap() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /main-affinity.rs: -------------------------------------------------------------------------------- 1 | use std::{thread, time::Duration}; 2 | 3 | fn main() { 4 | let arg = std::env::args().nth(1); 5 | let pin_to_core = arg.as_deref() == Some("--pin-to-core"); 6 | 7 | let core_ids = core_affinity::get_core_ids().unwrap(); 8 | 9 | let threads: Vec<_> = (0..10_000u32) 10 | .zip(core_ids.iter().cycle().copied()) 11 | .map(|(i, core_id)| { 12 | thread::spawn(move || { 13 | if pin_to_core { 14 | core_affinity::set_for_current(core_id); 15 | } 16 | let bad_hash = i.wrapping_mul(2654435761) % 200_000; 17 | thread::sleep(Duration::from_micros(bad_hash as u64)); 18 | for _ in 0..1000 { 19 | thread::sleep(Duration::from_millis(10)); 20 | } 21 | }) 22 | }) 23 | .collect(); 24 | 25 | for t in threads { 26 | t.join().unwrap() 27 | } 28 | } 29 | --------------------------------------------------------------------------------