使用 Flow,我尝试查看是否可以充分利用 CPU 内核。
处理内容是用随机数求周长比(我想不出合适的处理内容,所以很简单的问题)
随机数的产生、判断、计数组成一个三级管道。我使用 Enum/Flow 比较了每个进程。
结果
| 函数名 | 随机数发生器 | 判断 | 数数 | 执行时间处理时间 |
|---|---|---|---|---|
| calc_pi_with_enum | 枚举 | 枚举 | 枚举 | 5.065 |
| calc_pi_with_flow | 流动 | 流动 | 枚举 | 0.690 |
| calc_pi_with_flow_reduce | 流动 | 流动 | 流动 | 0.475 |
5.065/0.475 = 10.66
快 10 倍
执行结果详情
$ mix run bench/cutorial003_bench.exs
Operating System: Linux
CPU Information: AMD Ryzen 7 PRO 5750G with Radeon Graphics
Number of Available Cores: 16
Available memory: 15.29 GB
Elixir 1.13.4
Erlang 24.3.4.2
Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
reduction time: 0 ns
parallel: 1
inputs: none specified
Estimated total run time: 21 s
Benchmarking Enum ...
Benchmarking Flow (count) ...
Benchmarking Flow (reduce) ...
Name ips average deviation median 99th %
Flow (reduce) 2.10 475.37 ms ±3.28% 474.21 ms 500.76 ms
Flow (count) 1.45 690.81 ms ±4.28% 686.25 ms 742.75 ms
Enum 0.197 5065.95 ms ±0.00% 5065.95 ms 5065.95 ms
Comparison:
Flow (reduce) 2.10
Flow (count) 1.45 - 1.45x slower +215.44 ms
Enum 0.197 - 10.66x slower +4590.58 ms
测试程序
教程003.ex
defmodule Tutorial003 do
def gen_rand(_) do
{:rand.uniform(), :rand.uniform()}
end
def calc_pi_with_enum() do
hit =
1..10_000_000
|> Enum.map(&gen_rand(&1))
|> Enum.map(fn {x, y} -> x * x + y * y < 1 end)
|> Enum.count(fn bool -> bool end)
hit / 10_000_000 * 4
end
def calc_pi_with_flow() do
hit =
1..10_000_000
|> Flow.from_enumerable()
|> Flow.map(&gen_rand(&1))
|> Flow.map(fn {x, y} -> x * x + y * y < 1 end)
|> Enum.count(fn bool -> bool end)
hit / 10_000_000 * 4
end
def calc_pi_with_flow_reduce() do
hit =
1..10_000_000
|> Flow.from_enumerable()
|> Flow.map(&gen_rand(&1))
|> Flow.map(fn {x, y} -> x * x + y * y < 1 end)
|> Flow.reduce(fn -> 0 end, fn entry, acc ->
if(entry, do: acc + 1, else: acc)
end)
|> Flow.on_trigger(fn count -> {[count], count} end)
|> Enum.sum()
hit / 10_000_000 * 4
end
end
tutorial003_bench.exs
Benchee.run(
%{
"Enum" => fn _ -> Tutorial003.calc_pi_with_enum() end,
"Flow (count)" => fn _ -> Tutorial003.calc_pi_with_flow() end,
"Flow (reduce)" => fn _ -> Tutorial003.calc_pi_with_flow_reduce() end
},
before_each: fn _ -> :rand.seed(:exsss, {100, 101, 102}) end
)
CPU 利用率
执行期间的 CPU 利用率。
由于三个进程是依次执行的,所以我用红框直观地标出了它们切换的时间。
概括
枚举/流速比较
- 比 Enum 和 Flow 快 10 倍
- 我们能够确认,通过使用 Flow,CPU 能够以 80-90% 的速度运行。
- 因为在 Enum 的情况下是 10 到 15%,所以它似乎是一个核心 (1/8) 的处理能力。
- 在 8 个内核工作的情况下,流速度足够快。
- 之所以比核数快,可能是线程的影响(8核16线程的CPU),或者Enum的情况下,可能有1个CPU不行的缺点。
关于流量
- 如果您使用 Flow,您可以将处理划分并以一种很好的方式分配给每个 CPU。
- Flow.map() 易于使用。
- 单独使用 Flow.map() 相当快,但如果您使用 Flow.reduce 来整合结果,它可能会更快。
* 与@zacky1972 的结果一样,加速程度似乎因 CPU 类型和版本而异。
原创声明:本文系作者授权爱码网发表,未经许可,不得转载;
原文地址:https://www.likecs.com/show-308623900.html