用 Zig 实现 yes 命令

2022-07-26 16:52:55 浏览数 (1)

用 Zig 实现 yes 命令

起因是看到一篇文章[1],作者介绍了如何用 Rust 优化 yes 命令,第一个 buffer 的版本还比较好懂,第二个复用 buffer 的就没有那么直接了。想了下用 Zig 实现会是怎么样?于是就有了下面的测试:

测试时会用到 pv[2] 命令,需要单独安装

Buffer Write 版本

代码语言:javascript复制
const std = @import("std");

pub fn main() !void {
    const argv = std.os.argv;

    const output: []const u8 = if (argv.len > 1)
        argv.ptr[1][0..std.mem.len(argv.ptr[1])]
    else
        "y";

    const out = std.io.getStdOut();
    var f = std.io.bufferedWriter(out.writer());
    while ((try f.write(output)) > 0) {
        _ = try f.write("n");
    }
}

编译运行

代码语言:javascript复制
zig build-exe yes.zig -Drelease-safe
./yes | pv -r > /dev/null

大概是 116Mib/s

复用 Buffer 版本

代码语言:javascript复制
const std = @import("std");

const BUFFER_CAP = 64 * 1024;

fn fill_up_buffer(buf: *[BUFFER_CAP]u8, output: []const u8) []const u8 {
    if (output.len > buf.len / 2) {
        return output;
    }

    std.mem.copy(u8, buf, output);
    std.mem.copy(u8, buf[output.len..], "n");
    var buffer_size = output.len   1;
    while (buffer_size < buf.len / 2) {
        std.mem.copy(u8, buf[buffer_size..], buf[0..buffer_size]);
        buffer_size *= 2;
    }

    return buf;
}

pub fn main() !void {
    const argv = std.os.argv;

    const output: []const u8 = if (argv.len > 1)
        argv.ptr[1][0..std.mem.len(argv.ptr[1])]
    else
        "y";

    var buffer: [BUFFER_CAP]u8 = undefined;
    const body = fill_up_buffer(&buffer, output);
    const stdout = std.io.getStdOut();
    var writer = stdout.writer();
    while ((try writer.write(body)) > 0) {}
}

同样的方式编译执行,速率大概是: 5.4Gib/s

而且,这个版本相比 Rust 的实现,个人感觉,要清晰不少。

引用链接

[1] 一篇文章: https://endler.dev/2017/yes/ [2] pv: https://linux.die.net/man/1/pv

0 人点赞