【发布时间】:2019-06-26 08:23:00
【问题描述】:
我用 Elixir 做了一个多进程插入排序程序。但是,在 32 核机器上运行时,它比单进程插入排序要慢。 如果发送消息的进程运行在不同的核心上,我认为核心之间的同步可能是延迟的原因。有没有办法找出哪些进程在哪些内核上运行,或者如何控制哪些进程在哪些内核上运行?
defmodule Insertion do
def insert(l, x) do
case l do
[h | hs] -> if x < h, do: [x | l], else: [h | insert(hs, x)]
[] -> [x]
_ -> inspect l
end
end
def insertion_sort(l, x, []) do
insert(l, x)
end
def insertion_sort(l, x, [y | ys]) do
insert(l, x)
|> insertion_sort(y, ys)
end
def sort(l) do
case l do
[] -> l
[_] -> l
[x | [y | xs]] -> insertion_sort([y], x, xs)
end
end
#
# Parallel
#
def send_to_next(x, y, :end) do
insert_par(x, spawn(Insertion, :insert_par, [y, :end]))
end
def send_to_next(x, y, p) do
send p, y
insert_par(x, p)
end
def insert_par(x, next) do
receive do
{:ret, p} -> send p, {x, next}
y -> if x < y, do: send_to_next(x, y, next), else: send_to_next(y, x, next)
end
end
def insertion_sort_par([], _) do
end
def insertion_sort_par([x | xs], p) do
send p, x
insertion_sort_par(xs, p)
end
def ret_val(l, p) do
send p, {:ret, self()}
receive do
{x, :end} -> [x | l]
{x, next} -> ret_val([x | l], next)
end
end
def sort_par([]) do
[]
end
def sort_par([x | xs]) do
root = spawn(Insertion, :insert_par, [x, :end])
IO.puts inspect :timer.tc(Insertion, :insertion_sort_par, [xs, root])
ret_val([], root)
|> Enum.reverse
end
def run(n) do
x = floor :math.pow(10, n)
l = Enum.map(1..x, fn _ -> floor :rand.uniform * x end)
:timer.tc(Insertion, :sort_par, [l])
|> inspect
|> IO.puts
end
end
【问题讨论】:
-
我猜你可以通过 BEAM 虚拟机控制 + 监控 - erlang.org/doc/man/erlang.html#system_flag_schedulers_online 可能值得一试
-
您可以使用
erlang:system_info(scheduler_id)检查当前进程正在运行的调度程序。请注意,除非使用erl +sbt和其他标志绑定,否则调度程序可能会在内核之间移动。 -
我相信您可以(通过命令行)限制 Elixir 将使用的处理器数量。检查 +A 和 +P 标志。查看here 了解有关这些标志的更多详细信息。老实说,就哪些内核正在运行哪些进程而言,答案是“你不应该关心”。我对假设性能取决于哪个内核正在运行哪个进程的方法持怀疑态度。
-
@OnorioCatenacci 在针对大型列表运行程序时,我使用 + P 选项来增加进程数。但是,不使用 + A 选项。线程数是什么意思?
-
@legoscia 您的回答对我很有帮助。通过递归调用重复调用的进程是否可能在每次调用时移动调度程序?如果是这样,有没有办法将进程锁定到特定的调度程序?
标签: performance parallel-processing erlang elixir beam