【问题标题】:How do I share data between worker processes in Elixir?如何在 Elixir 的工作进程之间共享数据?
【发布时间】:2017-08-16 23:09:59
【问题描述】:

我有 2 个工人

worker(Mmoserver.MessageReceiver, []),
worker(Mmoserver.Main, [])

MessageReceiver 将等待直到在 TCP 上接收到消息并处理它们,主循环将获取该信息并对其采取行动。如何将worker1获取的信息分享给worker2?

Mmoserver.ex
这是启动workers的主文件

defmodule Mmoserver do
  use Application

  def start(_type, _args) do
    import Supervisor.Spec, warn: false

    IO.puts "Listening for packets..."

    children = [
      # We will add our children here later

      worker(Mmoserver.MessageReceiver, []),
      worker(Mmoserver.Main, [])
    ]

    # Start the main supervisor, and restart failed children individually
    opts = [strategy: :one_for_one, name: AcmeUdpLogger.Supervisor]
    Supervisor.start_link(children, opts)
  end

end

MessageReceiver.ex
这只会启动一个 tcp 侦听器。它应该能够获取一条消息,找出它是什么(通过它的 id)然后解析数据并将其发送到 Main 中的特定函数

defmodule Mmoserver.MessageReceiver do
  use GenServer
  require Logger

  def start_link(opts \\ []) do
    GenServer.start_link(__MODULE__, :ok, opts)
  end

  def init (:ok) do
    {:ok, _socket} = :gen_udp.open(21337)
  end

  # Handle UDP data
  def handle_info({:udp, _socket, _ip, _port, data}, state) do
    parse_packet(data)
    # Logger.info "Received a secret message! " <> inspect(message)
    {:noreply, state}
  end

  # Ignore everything else
  def handle_info({_, _socket}, state) do
    {:noreply, state}
  end

  def parse_packet(data) do
    # Convert data to string, then split all data
    # WARNING - SPLIT MAY BE EXPENSIVE
    dataString = Kernel.inspect(data)
    vars = String.split(dataString, ",")

    # Get variables
    packetID = Enum.at(vars, 0)
    x = Enum.at(vars, 1)

    # Do stuff with them
    IO.puts "Packet ID:"
    IO.puts packetID
    IO.puts x

    # send data to main
    Mmoserver.Main.handle_data(vars)
  end
end

Main.ex
这是主循环。它将处理 tcp 侦听器收到的所有最新数据并对其采取行动。最终它也会更新游戏状态。

defmodule Mmoserver.Main do
  use GenServer

  @tickDelay 33

  def start_link(opts \\ []) do
    GenServer.start_link(__MODULE__, [], name: Main)
  end

  def init (state) do

    IO.puts "Main Server Loop started..."

    # start the main loop, parameter is the initial tick value
    mainLoop(0)

    # return, why 1??
    {:ok, 1}
  end

  def handle_data(data) do
    GenServer.cast(:main, {:handle_data, data})
  end

  def handle_info({:handle_data, data}, state) do
    # my_function(data)
    IO.puts "Got here2"
    IO.puts inspect(data)
    {:noreply, state}
  end

  # calls respective game functions
  def mainLoop(-1) do
    IO.inspect "Server Loop has ended!" # base case, end of loop
  end

  def mainLoop(times) do
    # do shit
    # IO.inspect(times) # operation, or body of for loop

    # sleep
    :timer.sleep(@tickDelay);

    # continue the loop RECURSIVELY
    mainLoop(times + 1)
  end

end

【问题讨论】:

    标签: networking erlang udp elixir


    【解决方案1】:

    因为Mmoserver.MessageReceiver 将向Mmoserver.Main 发送消息,所以Main 必须首先启动,另外,它需要关联名称:

    worker(Mmoserver.Main, []),
    worker(Mmoserver.MessageReceiver, [])
    

    最简单的方法可能是,在您的Mmoserver.Main 中,假设它是GenServer

    defmodule Mmoserver.Main do
      use GenServer
    
      def start_link do
        GenServer.start_link(__MODULE__, [], name: :main)
      end
    
      # ...
    end
    

    您可以添加便利功能,以及如下实现:

    defmodule Mmoserver.Main do
      # ...
    
      def handle_data(data) do
        GenServer.cast(:main, {:handle_data, data})
      end
    
      def handle_info({:handle_data, data}, state) do
        my_function(data)
        {:noreply, state}
      end
    end
    

    所以,您的MessageReceiver 可以发送如下消息:

    defmodule Mmoserver.MessageReceiver do
      def when_data_received(data) do
        Mmoserver.Main.handle_data(data)
      end
    end
    

    这假设Mmoserver.MessageReceiver 不期望Mmoserver.Main 做出响应。我决定这样做,因为您没有指定要处理数据的方式,这似乎是如何执行此操作的简单示例。

    【讨论】:

    • 可能还值得一提的是考虑GenStage
    • 这看起来可能有效,但 udp 侦听器将无法工作,除非它首先被调用。这可能与 Main 启动一个不会中断的循环有关。我将调用按我的顺序放回去,udp 侦听器工作,当消息通过handle_data 时是callend 但不是handle_info。不知道为什么,我刚刚把代码放在我的帖子里
    • 这也让我担心 main 阻塞了 tcp 监听器,因为我需要两个进程都是异步的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 2012-03-19
    • 1970-01-01
    相关资源
    最近更新 更多