请提出将下面的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);
可以通过获得好处的长生不老药并发实现吗?
编辑: 有一点背景,我对长生不老药还是新鲜的,仍然在学习。该问题的主要动机是编写比应用并发更多的惯用e剂代码。
答案 0 :(得分:7)
要完全实现所写内容的最简单方法是使用for
宏:
sum =
for i <- 0..100,
j <- 0..1_000,
k <- 0..10_000,
reduce: 0 do
acc -> acc + 1
end
编辑:
:reduce
选项在Elixir的新版本(1.8+)中可用。在旧版本中,您可以使用嵌套的Enum.reduce/3
:
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)
关于问题的第二部分:否,此循环不会从并发中获得太多收益,并且如果以任何方式更改时间,那么只会更慢。在这种特殊情况下,它可以写为sum = 100 * 1_000 * 10_000
,它的速度可能更快,因为编译器可以很容易地将其优化为10_000_000
(IIRC Erlang编译器无法优化给定的常量循环)。
TL; DR 这种明显的循环无法通过并发来改善,通常情况下,很难说进程(aka并行化)是否会有所帮助。记住parallel != concurrent
也是非常重要的,因此,在具有N
调度程序(默认为CPU数量)的计算机上运行N-1
Erlang的进程不会使您加速。
答案 1 :(得分:1)
以下是一个有效的示例,说明了如何实现并发性,实现了1000000000个增量操作,以防万一,您可能会对如何做到这一点感到好奇。
下面的代码产生与您的外循环相对应的100个Elixir进程。因此,内部代码-这两个嵌套循环-(使用Enum.reduce
see以更惯用的形式编写)同时运行(由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
see docs ,可以使相对于纯并发获得并行优势来获得优势。
非正式速度测试 在我的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。