在Elixir中编写嵌套循环的更好方法
请建议更好的方法(更多的长生不老药方法)将下面的C代码写入长生不老药在Elixir中编写嵌套循环的更好方法,elixir,Elixir,请建议更好的方法(更多的长生不老药方法)将下面的C代码写入长生不老药 int some_num = 0; for(int i = 0; i < 100; i++){ for(int j = 0; j < 1000; j++){ for(int k = 0; k < 10000; k++){ some_num += 1; } } } printf("%d", some_num); int some_num=0; 对于(int i=0;i
int some_num = 0;
for(int i = 0; i < 100; i++){
for(int j = 0; j < 1000; j++){
for(int k = 0; k < 10000; k++){
some_num += 1;
}
}
}
printf("%d", some_num);
int some_num=0;
对于(int i=0;i<100;i++){
对于(int j=0;j<1000;j++){
对于(int k=0;k<10000;k++){
一些_num+=1;
}
}
}
printf(“%d”,数字);
而且,它可以通过获得好处elixir并发来实现吗
编辑:
有点背景,我对长生不老药还很新鲜,还在学习。这个问题的主要动机是编写更多惯用的长生不老药代码,而不是应用并发性。下面是一个工作示例,说明如何实现并发性,以解决实现100000000个增量操作这一相当棘手的问题,以防您对如何实现它感到好奇。 下面的代码生成了100个对应于外部循环的Elixir进程。内部代码——这两个嵌套循环(使用
Enum.reduce
以更惯用的形式编写)因此是并发运行的(尽可能由VM运行)。每个进程的结果都被发送到一个专用的接收进程,每当接收到新的结果时,该进程从100开始倒计时。每个小计都会被加到总计中,当收到100个小计时,总计会被打印出来。
测试:将代码保存为文件nested.ex
,并使用c nested.ex
在Elixir shell中编译。使用Main.Main
在该shell中运行它。您应该看到以下输出:
iex(4)> Main.main
:ok
total = 1000000000
当ok
在total
之前几秒钟出现时。您还应该体验高cpu多核使用率
defmodule Main do
def main( ) do
pid = spawn fn -> Receiver.loop( 100,0 ) end
1..100 |> Enum.each( fn x -> spawn (fn -> Nested.run(pid) end ) end)
end
end
#################################
defmodule Nested do
def run(pid) do
sub_total=
Enum.reduce( 1..1000, 0, fn x, acc_n -> acc_n +
Enum.reduce( 1..10000, 0, fn y, acc_m -> acc_m + 1 end )
end )
send pid, sub_total
Process.exit(self(), :kill )
end
end
#################################
defmodule Receiver do
def loop(0, total) do
IO.puts "total = #{total}"
Process.exit(self(), :kill )
end
#
def loop(count_down, total ) do # count down to zero collecting totals
receive do
sub_total ->
loop(count_down-1, sub_total + total)
end
end
end
#################################
通过明智地将普通spawn
转换为Node.spawn
非正式速度测试
在我的Win10 PC上测试,报告:
Erlang/OTP 20 [erts-9.0] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10]
Interactive Elixir (1.8.2) ..
我在这里给出的代码以16秒计算结果,其中@Hauleth的计算时间超过10分钟,因为他的似乎只分配了一个内核,而我的则得到了全部4个内核。实现您所写内容的最简单方法是使用
for
宏:
sum =
for i <- 0..100,
j <- 0..1_000,
k <- 0..10_000,
reduce: 0 do
acc -> acc + 1
end
关于问题的第二部分:否,这个循环不会从并发中获得太多好处,如果它会以任何方式改变时间,那么它只会更慢。在这种特殊情况下,它可以写为
sum=100*1_000*10_000
,这可能更快,因为编译器可以轻松地将其优化为10_000
(IIRC Erlang编译器无法将给定循环优化为常量)
TL;DR这种明显的循环无法通过并发性得到改善,在一般情况下,很难说进程(也称为并行化)是否会有所帮助。记住
parallel!=并发的
,因此在带有N-1
调度器的机器上运行N
Erlang进程不会获得任何加速(默认CPU数量)。增量是一种可以单独完成的操作-因此它是Elixir用于的任务的非典型。但是您可以将每个内部循环划分为4个独立的erlang/elixir进程,并在每个进程完成时接收来自该进程的消息来收集它们的结果。我说是因为我的电脑有4个核心。ymmv.Elixir中最先进的并发处理方法是采用流模块,但调整示例以使用它意味着首先将代码更改为更具Elixir风格的代码。@GavinBrelstaff:您指向了错误的库。如果您可以指向正确的库,我找不到如何在不调用mix等的情况下使用流模块。为什么你产生了这么多进程吗?@Hauleth这是Elixir/Erlang的方式-产生
许多小进程,让虚拟机进行并发优化。100不是那么多。我知道Erlang,当然这既不是Erlang方式,也不是任何类型的优化。如果有什么问题的话,那只会导致减速。“Erlang方法”是编写sum=100*1_000*10_000
。Hauleth GavinBrelstaff我是elixir的新手,只是想知道如何在elixir中编写更多惯用的嵌套循环,我们能从elixir的并发性中获得任何好处。不幸的是,这些琐碎的问题几乎永远不会给你一个真实世界的答案。这只是展示了一种可以尝试将并发性引入应用程序的方法。这可能不是解决您可能遇到的所有问题的最佳方法。如果您考虑的是真实世界的场景,最好询问一下。for宏的从何而来?Elixir shell提供了(CompileError)iex:3:不支持的选项:为您发布的其他代码提供了reduce to
。可能您的Elixir旧版本不支持:reduce
选项。Hi@Hauleth在现实世界中(我的4核Win10 PC)您的代码甚至需要很长时间才能返回提示,而我给出的代码在16秒后终止,因为Erlang优化还没有那么好。在理论上(以及在一些编译器的实践中),它将是一个常数。仍然在这个玩具代码中,它可以因此获得一些东西,但最终Elixir希望直接编译到BEAM IR,然后可以优化此类代码,通过引入过程,您将阻止此类优化。正如前面所说,它可以用更好的方式编写,因此整个问题几乎毫无意义。+1用于提及新的:reduce
选项。奇怪的语法,箭头向各个方向移动——就像在for的语句中有一个分支case
语句。文档中有许多for选项
。
Enum.reduce(0..100, 0, fn _, acc ->
acc + Enum.reduce(0..1_000, 0, fn _, acc ->
acc + Enum.reduce(0..10_000, 0, fn _, acc ->
acc + 1
end)
end)
end)