在前面多语言测试中,遇到一个难以置信的问题,rust的输出到文件比c语言还快,这是不合情理的,通过对两者输出语句的比较,发现了不同。
rust程序在输出到stdout前有这么一句
let mut writer = BufWriter::with_capacity(64 * 1024, stdout.lock());
而c语言是直接输出。
将上述语句发给DeepSeek,它给出了等价的C语言实现。
#define BUFFER_SIZE (64 * 1024) // 64KB 缓冲区
// 设置 stdout 缓冲
char buffer[BUFFER_SIZE];
if (setvbuf(stdout, buffer, _IOFBF, sizeof(buffer)) != 0) {
perror("setvbuf failed");
return EXIT_FAILURE;
}
// 原输出语句
// 刷新缓冲区
if (fflush(stdout) != 0) {
perror("fflush failed");
return EXIT_FAILURE;
}
加入上述语句的c代码编译运行情况如下:
gcc sort_lines_buf.c -o csortbuf -O3
time ./csortbuf varchar.txt >vvc.txt
real 0m1.367s
user 0m0.431s
sys 0m0.086s
time ./csortbuf varchar.txt >/dev/null
real 0m0.792s
user 0m0.406s
sys 0m0.063s
而加入缓冲前
time ./c_sort varchar.txt >vvc.txt
real 0m3.568s
user 0m0.439s
sys 0m0.226s
time ./c_sort varchar.txt >/dev/null
real 0m0.758s
user 0m0.335s
sys 0m0.080s
可见,缓冲后输出到文件的时间缩短到原来的1/3,而不输出文件的保持不变。
需要指出,这个缓冲区并非越大越好,它受限于栈容量,如果改成从堆分配和文件大小一样的内存做缓冲区,反而比不缓冲更慢。
完整带缓冲输出c代码摘录如下。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define MAX_LINES 1000000 // 最多100万行
#define BUFFER_SIZE (64 * 1024) // 64KB 缓冲区
int compare_offsets(const void *a, const void *b) {
return strcmp(*(const char **)a, *(const char **)b);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return 1;
}
// 打开文件并获取大小
int fd = open(argv[1], O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
struct stat st;
if (fstat(fd, &st) == -1) {
perror("fstat");
close(fd);
return 1;
}
size_t file_size = st.st_size;
// 分配缓冲区并读取文件
char *buf = malloc(file_size + 1);
if (!buf) {
perror("malloc");
close(fd);
return 1;
}
if (read(fd, buf, file_size) != file_size) {
perror("read");
free(buf);
close(fd);
return 1;
}
close(fd);
buf[file_size] = '\0'; // 确保以null结尾
// 记录每行起始地址
char *lines[MAX_LINES];
size_t line_count = 0;
lines[line_count++] = buf; // 第一行开始
// 遍历缓冲区,记录每行起始地址并将\n替换为\0
for (char *p = buf; *p && line_count < MAX_LINES; p++) {
if (*p == '\n') {
*p = '\0';
if (*(p + 1)) { // 如果不是文件末尾
lines[line_count++] = p + 1;
}
}
}
// 对行指针数组进行排序
qsort(lines, line_count, sizeof(char *), compare_offsets);
// 设置 stdout 缓冲
char buffer[BUFFER_SIZE];
if (setvbuf(stdout, buffer, _IOFBF, sizeof(buffer)) != 0) {
perror("setvbuf failed");
return EXIT_FAILURE;
}
// 写入数据
for (int i = 0; i < line_count; i++) {
if (printf("%s\n", lines[i]) < 0) {
perror("printf failed");
return EXIT_FAILURE;
}
}
// 刷新缓冲区
if (fflush(stdout) != 0) {
perror("fflush failed");
return EXIT_FAILURE;
}
free(buf);
return 0;
}