我正在尝试将计算与rpc:pmap
并行化。但我对它的表现感到困惑。
这是一个简单的例子:
-module(my_module).
-compile(export_all).
do_apply( X, F ) -> F( X ).
首先 - 在单个节点上进行测试:
1> timer:tc( rpc, pmap, [{my_module, do_apply}, [fun(X) -> timer:sleep(10), X end], lists:seq(1,10000)] ).
{208198,
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27|...]}
之后我连接了第二个节点(我操作系统中的第二个erlang shell进程):
(foo@Stemm.local)24> timer:tc( rpc, pmap, [{my_module, do_apply}, [fun(X) -> timer:sleep(10), X end], lists:seq(1,10000)] ).
{446284,
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27|...]}
最后我连接了第三个节点:
(foo@Stemm.local)26> timer:tc( rpc, pmap, [{my_module, do_apply}, [fun(X) -> timer:sleep(10), X end], lists:seq(1,10000)] ).
{483399,
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27|...]}
所以 - 我有三个节点与单节点的性能更差。
我意识到节点之间的通信存在一些开销。但是,我如何理解在哪些情况下更好地在多个节点上执行计算?
修改
我从shell进行的逐步测试:
1> c(my_module).
{ok,my_module}
2>
2> List = lists:seq(1,10000).
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27,28,29|...]
在单个节点上测试性能:
3> timer:tc( rpc, pmap, [{my_module, do_apply}, [fun(X)-> timer:sleep(10), X end], List] ).
{207346,
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27|...]}
进入网络环境:
4> net_kernel:start([one]).
{ok,<0.20066.0>}
(one@Stemm.local)5> erlang:set_cookie(node(), foobar).
true
添加第二个节点:
(one@Stemm.local)6> net_kernel:connect('two@Stemm.local').
true
(one@Stemm.local)7>
(one@Stemm.local)7> nodes().
['two@Stemm.local']
使用两个节点测试性能:
(one@Stemm.local)8> timer:tc( rpc, pmap, [{my_module, do_apply}, [fun(X)-> timer:sleep(10), X end], List] ).
{510733,
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27|...]}
连接第三个节点:
(one@Stemm.local)9> net_kernel:connect('three@Stemm.local').
true
(one@Stemm.local)10> nodes().
['two@Stemm.local',
'three@Stemm.local']
使用三个节点测试性能:
(one@Stemm.local)11> timer:tc( rpc, pmap, [{my_module, do_apply}, [fun(X)-> timer:sleep(10), X end], List] ).
{496278,
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27|...]}
P.S。我想性能会下降,因为我在同一台物理机器上创建了每个节点作为新的erlang-shell进程。但我不确切地知道我是不对。
答案 0 :(得分:3)
您无需添加节点即可在Erlang中获得并行性。每个节点都可以在本地支持大量进程。 pmap
已经在并行运行您的函数。如果您等待的时间更长,则更容易看到:
timer:tc( rpc, pmap, [{my_module, do_apply}, [fun(X) -> timer:sleep(1000), X end], lists:seq(1,10000)] ).
{1158174,
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27|...]}
如果睡眠在一个节点上按顺序运行,那么您可以期望1000 * 10000 = 10,000,000
的最小等待时间,我们只需要等待1,158,174
您正在创建3个独立的Erlang VM,并将它们相互连接。然后,您正在其中一个VM上运行并行映射。其他虚拟机只会损害您当前设置的性能,因为他们都在尝试使用相同的物理资源,其中2个甚至没有运行任何工作。
多个节点只有在不同的物理资源上运行才能提高性能。