最常见的操作系统线程缺点是它们使用很多RAM.This在Linux上不是真的。
让我们使用10_000 Goroutines进行10_000 Linux线程的内存概要.WE SPAWN 10K工人,睡眠约10秒,每10毫秒醒来,唤醒工作者被伪随机延迟延误,最高达200毫秒,以避免雷鸣群问题。
使用std :: {thread,time :: duration}; fn main(){让mut threads = vec :: new();对于我在0u32 .. 10_000在0 .. 1000 {thread ::睡眠(持续时间:: from_millis(10));}};线程.push(t);对于线程{t .join().unwrap()}}
包主要导入(" sync""时间")func main(){var wg sync。等待i:= uint32(0);我< 10 _000; i ++ {wg。添加(1)go func(){defer wg。 DONE()BAD_HASH:=(i * 2654435761)%200 _000时间。睡眠(时间。持续时间(bad_hash)*时间。微秒)对于j:= 0; j< 1000; j ++ {时间。睡眠(10 *时间。毫秒)}}}()} wg。等待 () }
λRUSTCMAIN.RS -C OPT级别= 3&& ./t ./mainreal 10.35suser 4.96ssys 16.06srss94472kλgo build main.go&&& ./t ./mainreal 10.92suser 13.30ssys 0.55srss 34924k
一个线程只是Goroutine的3倍.Absolute数字也很重要:10k线程只需要100兆字节的开销。如果应用程序执行10k并发的东西,100MB可能会忽略不计。
请注意,使用该基准测试是错误的,以比较线程和Goroutines的性能。工作负载是用于测量绝对存储器开销的代表性,但不代表时间开销。
已经说,可以解释为什么线程需要21秒的CPU时间,而Goroutines只需要14.Go运行时每次CPU核心的线程,并且难以将每个Goroutine保持与特定线程(并且,通过扩展, CPU)。默认情况下,默认迁移CPU之间的迁移,它会在同步开销中引入循环的线程,以循环方式删除此开销: λ货物构建 - && ./t ./target/release/main -pin-to-core完成版本[优化]目标在0.36suser 3.01ssys 9.08srs 94856k 现在的CPU时间大致相同,但分布不同。此工作负载,Goroutine Scheduler在线调度程序在内核中花费大致相同的循环。