Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Elixir中编写嵌套循环的更好方法_Elixir - Fatal编程技术网

在Elixir中编写嵌套循环的更好方法

在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

请建议更好的方法(更多的长生不老药方法)将下面的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<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)