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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/11.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阻塞的GenServer进程_Elixir_Blocking_Gen Server - Fatal编程技术网

Elixir阻塞的GenServer进程

Elixir阻塞的GenServer进程,elixir,blocking,gen-server,Elixir,Blocking,Gen Server,我有一个简单的GenServer,我希望在其中创建一个循环,每两秒钟调用一个函数: defmodule MyModule do use GenServer def start_link(time) do GenServer.start_link(__MODULE__,time) end #Start loop def init(time) do {:ok, myLoop(time)} end #Loop every two seconds d

我有一个简单的
GenServer
,我希望在其中创建一个循环,每两秒钟调用一个函数:

defmodule MyModule do
  use GenServer

  def start_link(time) do
    GenServer.start_link(__MODULE__,time)
  end

  #Start loop
  def init(time) do
    {:ok, myLoop(time)}
  end

  #Loop every two seconds
  def myLoop(time) do

    foo = bah(:someOtherProcess, {time})
    IO.puts("The function value was: #{foo}")
    :timer.sleep(2000)
    myLoop(time + 2)
  end
end 
但当我打电话时:

{:ok, myServer} =MyModule.start_link(time)
IO.puts("Now I can carry on...")
我从来没有看到过上述电话的回音。我想这是很明显的。所以我的问题是,如何创建我想要的循环,而不阻塞下游执行任务的流程


谢谢。

因为您在init函数中调用循环,所以循环会无限阻塞,回调永远不会返回

在init上执行操作的一种常见技术是向GenServer发送一条消息并用于执行操作。执行此操作时,应记住为
handle\u info
包含一个全面信息

defmodule MyModule do
  use GenServer

  def start_link(time) do
    {:ok, pid} = GenServer.start_link(__MODULE__,time)
    send(pid, {:start_loop, time})
    {:ok, pid}
  end

  #Start loop
  def init(time) do
    {:ok, nil}
  end

  def handle_info({:start_loop, time}, state) do
    myLoop(time)
    {:noreply, state}
  end

  #catch all
  def handle_info(_, state) do
    {:noreply, state}
  end    

  #Loop every two seconds
  def myLoop(time) do
    IO.puts("The function value was: #{time}")
    :timer.sleep(2000)
    myLoop(time + 2)
  end
end 

由于在init函数中调用循环,因此循环会无限阻塞,并且回调永远不会返回

在init上执行操作的一种常见技术是向GenServer发送一条消息并用于执行操作。执行此操作时,应记住为
handle\u info
包含一个全面信息

defmodule MyModule do
  use GenServer

  def start_link(time) do
    {:ok, pid} = GenServer.start_link(__MODULE__,time)
    send(pid, {:start_loop, time})
    {:ok, pid}
  end

  #Start loop
  def init(time) do
    {:ok, nil}
  end

  def handle_info({:start_loop, time}, state) do
    myLoop(time)
    {:noreply, state}
  end

  #catch all
  def handle_info(_, state) do
    {:noreply, state}
  end    

  #Loop every two seconds
  def myLoop(time) do
    IO.puts("The function value was: #{time}")
    :timer.sleep(2000)
    myLoop(time + 2)
  end
end 

最好运行另一个处理计时器循环的进程,并让它在执行操作时向genserver发送消息。这样,GenEvent进程在处理其他消息时大部分处于空闲状态,但它将在应该采取定期操作时收到通知

您可以通过使用
spawn\u link
在自己的进程中运行
MyModule.myloop
函数来实现这一点。这方面的一个例子如下:

defmodule MyModule do
  use GenServer

  def start_link(time) do
    GenServer.start_link(__MODULE__,time)
  end

  #Start loop
  def init(time) do
    spawn_link(&(MyModule.myloop(0, self))
    {:ok, nil}
  end

  def handle_info({:timer, time}, state) do
    foo = bah(:someOtherProcess, {time})
    IO.puts("The function value was: #{foo}")
    {:noreply, state}
  end 
  def handle_info(_, state) do
    {:noreply, state}
  end

  #Loop every two seconds
  defp myLoop(time, parent) do
    send(parent, {:timer, time})
    :timer.sleep(2000)
    myLoop(time + 2)
  end
end 

如果您不太在意将时间作为消息的一部分传入(您可以根据GenServer状态或类似情况计算时间),您可以使用erlang函数
:timer.send_interval
,它将在每个周期发送一条消息,类似于上面的
myLoop
函数。文档如下:

最好运行另一个处理计时器循环的进程,并让它在执行操作时向genserver发送消息。这样,GenEvent进程在处理其他消息时大部分处于空闲状态,但它将在应该采取定期操作时收到通知

您可以通过使用
spawn\u link
在自己的进程中运行
MyModule.myloop
函数来实现这一点。这方面的一个例子如下:

defmodule MyModule do
  use GenServer

  def start_link(time) do
    GenServer.start_link(__MODULE__,time)
  end

  #Start loop
  def init(time) do
    spawn_link(&(MyModule.myloop(0, self))
    {:ok, nil}
  end

  def handle_info({:timer, time}, state) do
    foo = bah(:someOtherProcess, {time})
    IO.puts("The function value was: #{foo}")
    {:noreply, state}
  end 
  def handle_info(_, state) do
    {:noreply, state}
  end

  #Loop every two seconds
  defp myLoop(time, parent) do
    send(parent, {:timer, time})
    :timer.sleep(2000)
    myLoop(time + 2)
  end
end 

如果您不太在意将时间作为消息的一部分传入(您可以根据GenServer状态或类似情况计算时间),您可以使用erlang函数
:timer.send_interval
,它将在每个周期发送一条消息,类似于上面的
myLoop
函数。文档在这里:

完成您要做的事情的最好/最干净的方法是使用
过程。在/3
之后发送。它将超时委托给调度程序,而不是另一个进程

defmodule MyModule do
  use GenServer

  def start_link(time) do
    GenServer.start_link(__MODULE__,time)
  end

  def init(time) do
    schedule_do_something(time)
    {:ok, %{time: time}}
  end

  def handle_info(:do_something, state) do
    %{time: time} = state
    # do something interesting here
    schedule_do_something(time)
    {:noreply, state}
  end

  defp schedule_do_something(time_in_seconds) do
    Process.send_after(self, :do_something, (time_in_seconds * 1000))
  end
end

不管怎样,GenServer就像一个事件循环,那么为什么要自己重新实现它呢?

要完成您要做的事情,最好/最干净的方法是使用
进程。在/3之后发送。它将超时委托给调度程序,而不是另一个进程

defmodule MyModule do
  use GenServer

  def start_link(time) do
    GenServer.start_link(__MODULE__,time)
  end

  def init(time) do
    schedule_do_something(time)
    {:ok, %{time: time}}
  end

  def handle_info(:do_something, state) do
    %{time: time} = state
    # do something interesting here
    schedule_do_something(time)
    {:noreply, state}
  end

  defp schedule_do_something(time_in_seconds) do
    Process.send_after(self, :do_something, (time_in_seconds * 1000))
  end
end

GenServer的行为就像一个事件循环,那么为什么要自己重新实现呢?

有一个内置函数
:timer.send\u interval/2
可以做你需要做的事情,而不需要自己编写代码。有一个内置函数
:timer.send\u interval/2
可以做你需要做的事情,而不需要自己编写代码。