Elixir遍历/proc/stat列表并生成CPUCore结构体方法问询
问题:如何将/proc/stat行数据映射到Elixir结构体字段?
以下是我练习读取/proc/stat的代码:
defmodule CpuUsage.Reader do use Task, CPUCore @path "\/proc\/stat" @cores 6 @spec start_link(any) :: {:ok, pid} def start_link(_arg) do Task.start_link(&loop/0) end @spec loop :: no_return def loop() do File.stream!(@path) |> Stream.map(&String.split(&1, "\n", trim: true)) |> Enum.slice(0, @cores) |> core_list = [ new_head | core_list] = [CPUCore.coresToStruct | _ ] end end defmodule CPUCore do defstruct [:number, :user , :nice , :system , :idle , :iowait , :irq , :softirq] @spec coresToStruct(any, any) :: none def coresToStruct([head | tail], iteration \\ 0) do key_list = [:number, :user, :system, :idle, :iowait, :irq, :softirq] core_list = [head | tail] coreStruct = %CPUCore{} String.split(head, " ", trim: true) |> Enum.reduce(key_list, fn(x, key_list, coreStruct) -> %CPUCore{key_list: x} end) if @cores - iteration > 2 do new_list = [core_list[1] | Enum.slice(core_list, 2, @cores - iteration)] coresToStruct(iteration + 1) end end end
我需要解决的问题是:如何遍历传入coresToStruct函数的列表首行,并将该行的各字符串分别赋值给CPUCore结构体的number、user等对应字段?
解决方案
先修正原代码中的语法错误,再实现行数据到结构体的映射:
1. 修正基础问题
@path不需要转义,直接写"/proc/stat"use Task, CPUCore错误,Task的use不需要额外参数,改为use Task- 移除
loop函数中语法错误的管道赋值逻辑,改用流式处理+映射转换
2. 实现行数据到结构体的映射
在CPUCore模块中新增from_line/1函数,通过模式匹配和类型转换直接完成字段赋值,逻辑更直观:
defmodule CPUCore do defstruct [ :number, :user, :nice, :system, :idle, :iowait, :irq, :softirq ] # 将/proc/stat的一行字符串转换为CPUCore结构体 def from_line(line) do # 拆分行内容,提取cpu编号和各项数值 ["cpu" <> num_str | raw_values] = String.split(line, ~r/\s+/, trim: true) number = String.to_integer(num_str) # 将字符串数值转成整数,匹配结构体字段顺序 [user, nice, system, idle, iowait, irq, softirq] = Enum.map(raw_values, &String.to_integer/1) # 直接构造结构体 %__MODULE__{ number: number, user: user, nice: nice, system: system, idle: idle, iowait: iowait, irq: irq, softirq: softirq } end end
3. 修正Reader模块的loop逻辑
过滤掉总CPU统计行("cpu"开头但不是"cpuN"的行),只提取指定数量的核心数据:
defmodule CpuUsage.Reader do use Task @path "/proc/stat" @cores 6 @spec start_link(any) :: {:ok, pid} def start_link(_arg) do Task.start_link(&loop/0) end @spec loop :: no_return def loop() do cpu_cores = File.stream!(@path) |> Stream.map(&String.trim/1) # 过滤出单个核心的统计行(排除总cpu行) |> Stream.filter(fn line -> String.starts_with?(line, "cpu") and line != "cpu" end) # 取指定数量的核心数据 |> Enum.take(@cores) # 转换为结构体列表 |> Enum.map(&CPUCore.from_line/1) # 这里可以添加处理逻辑,比如打印结果 IO.inspect(cpu_cores, label: "CPU Core Stats") # 每秒轮询一次(可选,根据需求调整) Process.sleep(1000) loop() end end
核心逻辑说明
- 用
String.split(line, ~r/\s+/, trim: true)拆分行内容,处理多个连续空格的情况 - 通过模式匹配
["cpu" <> num_str | raw_values]直接提取核心编号字符串,转成整数后赋值给:number字段 - 将剩余的数值字符串批量转成整数,按结构体字段顺序匹配赋值,逻辑清晰且不易出错
内容的提问来源于stack exchange,提问作者k1t3k
相关产品推荐
相关产品推荐

