guest@blog.cmj.tw: ~/posts $

Yes


Yes, you can

Yes 是一個 GNU core utils 內的一個小工具,他可以幫你快速印出 y 或者其他指定字串。 很顯然的、這是一個簡單的程式,但實際上他的 實作邏輯 比想像中的還要再複雜一點。

trivial solution

以 Rust 當作程式語言的範例、最簡單的實作方式如下:

fn main() {
	loop {
		println!("y");
	}
}

advanced solution

但是、如果你想要實作一個更加完整的版本、那麼你需要考慮到一些問題: 單一次只寫一個字串對於 I/O 來說效率太差。因此可以思考一次寫入一個 buffer 大小的字串。


fn main() {
	let buf = "y\n".repeat(4096);

	loop {
		println!("{}", buf);
	}
}

在這種情況下就可以減少 context switch 的次數並提升效率。

splice solution

參考了一下 uutils/coreutils 的實作方式、他是使用 splice 來做的。這個指令是一個 Linux 特有的 系統呼叫 , 跟 sendfile 類似,他可以將兩個 pipe 間的 file descriptor 做 kernel-space 內的資料傳遞、而不用再經過 user-space。 在這種情況下、除了可以減少 I/O 間的 context switch 之外、還可以減少 user-space 與 kernel-space 間的 context switch。

Benchmark

為了可以評斷上面幾種方式的效能、在 Terminal 環境下使用 Pipe 加上 head 指令來做效能測試: time your_program | head -n 1000000

method time
trivial 0m1.056s
buffer (4096) 0m0.842s