Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/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,假设我有这个模块 defmodule Loader do def spawn_pools(0, host, iteations, pids) do launch!(pids) #something I want to achieve end def spawn_pools(pools, host, iterations, pids) do pid = spawn_link(__MODULE__, :siege, [host, iterations]) sp

假设我有这个模块

defmodule Loader do

  def spawn_pools(0, host, iteations, pids) do
    launch!(pids) #something I want to achieve
  end

  def spawn_pools(pools, host, iterations, pids) do
    pid = spawn_link(__MODULE__, :siege, [host, iterations])
    spawn_pools(pools-1, host, iterations, [pid|pids])
  end

end
所以,如果其他模块将执行
Loader.spawn\u池(10个,主机,迭代,[])
,它将产生10个执行方法的进程

问题是我希望它尽可能地并行——在同一时刻开始执行所有进程

所以我想到了这个

def siege do
  receive do
   {:launch} -> #...
  end
end
但这也给我带来了同样的问题——因此我需要同时向所有这些进程发送
:launch
。这让我想到了递归,同样问题的另一层


另外,我对Erlang/Elixir范式还不熟悉,所以我可能遗漏了什么

Erlang和Elixir在每个进程中按顺序执行代码;由于进程是从其他进程派生出来的,因此在语言的本质上,派生的行为是连续的。没有办法同步≥ 1过程。向每个进程发送一条消息以“同步”进程作业的启动有相同的问题:发送消息是顺序的,因此主进程仍将一次发送一条消息。即使将生成/消息发送分发到多个进程上,保证它们都在同一时间启动基本上是不可能的

但是,消息发送和进程生成都是非常快速的操作,因此问题通常很小


解决方案可以是在生成任何进程之前获取当前时间戳,并将其传递给每个新进程:该进程随后将获取其当前时间戳,减去初始时间戳,从而获取“以后”生成它的方式。您可以使用此信息来利用诸如计时器.sleep/1之类的功能来尝试和模拟同步启动,但它仍然受到时钟精度等方面的不同程度的影响:)。

最接近的方法是使用列表理解。它是一种语言结构,因此理论上可以编译为并行执行(但是,这不是由于后面描述的其他问题)。查看如何在官方的Erlang库中编写。这基本上是这样做的:

[spawn(fun() -> ReplyTo ! {self(), promise_reply, M:F(A)} end) || A <- ArgL]

请注意,在
start1
中,除了叶进程之外,还有更多的支持进程,它们只为生成子进程而存在。在第一种情况下,从开始到生成每个叶子树的时间似乎更短,但在我的环境中,它不希望在合理的时间内完成
N=5
。但是您可以采用这种想法或类似的方法,根据您的需要调整
N
以及每个进程产生的子进程的数量。

好吧,10个进程就是一个例子,我想到的是数千个,而不是微秒,但对于一半进程已经执行而另一半尚未生成的情况(我需要相对并发)。我的意思是,应该有一些标准的解决方案模式,erlang/elixir程序员使用这些模式?计算机很少同时运行一堆东西。他们做很多小事情的速度如此之快,以至于你认为他们在同一时间。Elixir/Erlang在将工作分配到所有可用的CPU内核方面做得很好,但每个内核“同时”只做一件事。即使这是可能的,您的实际并行性也将限于可用的CPU内核。您实际上是在问同时运行多个进程。它们是否都是在同一微秒内启动的都是无关紧要的,因为即使它们看起来是这样的,它们也不会真正隐藏起来。我只想启动你的进程,让虚拟机担心如何安排它们。你认为每个下一个进程发送上一个进程,比如
sleep\u,直到\u ready
消息,当我的
sakege
方法开始实际执行时,如果100毫秒内没有该消息,或者如果有消息,则循环。看来这是一个可能的解决方案你检查了我答案中的最后一个链接了吗?它说:我们观察到创建Erlang进程所需的时间是恒定的1µs,最多2500个进程;此后,它增加到大约3µs,用于多达30000个过程。因此,产生1000个进程可能需要1毫秒左右。我建议您在尝试优化代码之前进行一些基准测试。您可以使用的另一个技巧是启动进程树,而不是顺序启动它们,例如,让每个进程启动4个子进程。所以第一个过程开始4个孩子,每个孩子开始4个自己的孩子。。。。。等等五代进程将启动1024个进程。因此,根据您需要的进程数量,您可以允许前五代或六代进程在创建子进程后死亡,并且只在第七代进程中开始计算。VM调度程序可能会将其中一些进程移动到其他CPU。如您所建议的,使用消息同步已启动的进程是另一种选择,但调度程序可能会在其他进程有机会处理消息之前开始执行某些进程。
-module(spawner).

-export([start1/1, start2/1]).

start1(N) ->
    start_new1(erlang:monotonic_time(), self(), 4),
    loop(round(math:pow(4, N)), 0, []).

start_new1(Start, Pid, N) ->
    Fun = fun() -> child(Start, Pid, N-1) end,
    [spawn(Fun) || _ <- lists:seq(1, 4)].

child(Start, Pid, 0) -> send_diff(Start, Pid);
child(Start, Pid, N) -> start_new1(Start, Pid, N).

loop(All, All, Acc) ->
    {All, lists:sum(Acc)/All, lists:min(Acc), lists:max(Acc)};
loop(All, Y, Acc) ->
    receive Time -> loop(All, Y+1, [Time|Acc]) end.

send_diff(Start, Pid) ->
    Diff = erlang:monotonic_time() - Start,
    Pid ! erlang:convert_time_unit(Diff, native, micro_seconds).


start2(N) ->
    All = round(math:pow(4, N)),
    Pid = self(),
    Seq = lists:seq(1, All),
    Start = erlang:monotonic_time(),

    Fun = fun() -> send_diff(Start, Pid) end,
    [spawn(Fun) || _ <- Seq],
    loop(All, 0, []).
1> c(spawner).
{ok,spawner}
2> spawner:start1(4).
{256,868.8671875,379,1182}
3> spawner:start2(4).
{256,3649.55859375,706,4829}
4> spawner:start2(5).
{1024,2260.6494140625,881,4529}