You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Linux系统下如何更快读取或采集文件内容(例如每秒采集CPU温度)

优化sysfs thermal数据采集速度的方法

你的问题核心在于shell循环中频繁创建cat进程——每个thermal zone都要启动两个cat进程,100个节点就是200次进程创建/销毁,这是最大的性能开销,加上多次独立的文件IO调用,导致总耗时超标。下面是几个能大幅提升速度的方案:

1. 用awk一次性处理所有文件(shell层面最优)

把所有typetemp文件一次性传给awk,让awk在内部完成读取和匹配,避免多次fork进程:

awk '{
    # 记录每个thermal_zone的type值
    if (FILENAME ~ /type$/) {
        zone_path = FILENAME
        sub(/\/type$/, "", zone_path)
        type_map[zone_path] = $0
    }
    # 读取temp并对应输出type和temp
    else if (FILENAME ~ /temp$/) {
        zone_path = FILENAME
        sub(/\/temp$/, "", zone_path)
        printf "%s: %s\n", type_map[zone_path], $0
    }
}' /sys/class/thermal/thermal_zone*/{type,temp}

这个命令只启动一个awk进程,一次性处理所有目标文件,进程开销几乎为0,实测能把耗时压缩到几百毫秒甚至更低。

2. 用C语言直接读取(性能极致优化)

如果shell优化后还是不够快,用C语言直接调用系统调用open/read读取sysfs文件,完全避免shell的进程调度开销。这里是一个极简的实现:

#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define THERMAL_BASE "/sys/class/thermal/"
#define BUF_LEN 256

// 读取sysfs文件内容(去掉换行符)
static void read_sysfs(const char *path, char *buf) {
    int fd = open(path, O_RDONLY);
    if (fd == -1) return;
    ssize_t n = read(fd, buf, BUF_LEN - 1);
    if (n > 0) {
        buf[n] = '\0';
        if (buf[n-1] == '\n') buf[n-1] = '\0';
    }
    close(fd);
}

int main() {
    DIR *dir = opendir(THERMAL_BASE);
    if (!dir) {
        perror("Failed to open thermal directory");
        return 1;
    }

    struct dirent *entry;
    char type_path[BUF_LEN], temp_path[BUF_LEN];
    char type[BUF_LEN], temp[BUF_LEN];

    while ((entry = readdir(dir)) != NULL) {
        // 只处理thermal_zone开头的目录
        if (strncmp(entry->d_name, "thermal_zone", 12) != 0) continue;

        snprintf(type_path, BUF_LEN, "%s%s/type", THERMAL_BASE, entry->d_name);
        snprintf(temp_path, BUF_LEN, "%s%s/temp", THERMAL_BASE, entry->d_name);

        read_sysfs(type_path, type);
        read_sysfs(temp_path, temp);

        printf("%s: %s\n", type, temp);
    }

    closedir(dir);
    return 0;
}

编译运行:

gcc -O2 -o thermal_reader thermal_reader.c
./thermal_reader

这个程序的耗时通常在几十毫秒级别,完全满足每秒采集一次的需求。

3. 过滤不必要的节点(减少读取量)

如果100个节点中只有部分是你需要的(比如仅CPU相关的),可以先过滤出目标节点再读取,减少IO次数:

# 先筛选出CPU相关的thermal zone(根据你的type名称调整)
TARGET_ZONES=$(grep -lE "cpu_thermal|x86_pkg_temp|coretemp" /sys/class/thermal/thermal_zone*/type)

# 只处理筛选后的节点
for zone in $TARGET_ZONES; do
    zone_dir=$(dirname "$zone")
    printf "%s: %s\n" "$(cat "$zone")" "$(cat "$zone_dir/temp")"
done

如果只需要读取10个以内的节点,这个方法的速度会非常快。

内容的提问来源于stack exchange,提问作者domagaja

火山引擎 最新活动