You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 21:54:35