首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在Elixir中编写一个多事件驱动的if子句?

如何在Elixir中编写一个多事件驱动的if子句?
EN

Stack Overflow用户
提问于 2019-09-16 06:31:58
回答 2查看 90关注 0票数 0

我需要指定一种适合于高并发应用程序的语言(用于工业自动化目的,其要求类似于分布式在线游戏)。

假设一个case c依赖于两个变量ab。我们的代码应该是这样的(在Javascript中):

代码语言:javascript
运行
复制
if (a && b){
  c();
}

如果a是由不同的事件设置的,那么代码就会变得稍微复杂一些:

代码语言:javascript
运行
复制
on('a', function(a){
  if (a && b){
    c();
  }
});

如果ab都是由两个不同的事件设置的,事情就会变得更加复杂。一种解决方案可能是使用signal库:

代码语言:javascript
运行
复制
branch = new SignalBranch()
signal1 = branch.add()
on('a', function(a){
  if (a) {
    signal1.go()
  }
})
signal2 = branch.add()
on('b', function(b){
  if (b) {
    signal2.go()
  }
})
branch.joined(function(err, signals){
  c()
})

另一种方法是使用Promise:(取自this site的示例)

代码语言:javascript
运行
复制
var signal1 = new Promise(function(resolve){
  on('a', function(a){
    if (a) {
      resolve()
    }
  })
})
var signal2 = new Promise(function(resolve){
  on('b', function(b){
    if (b) {
      resolve()
    }
  })
})
Promise.all([signal1, signal2]).then(function(data) {
  c();
});

正如所见,实现(因此可读性)变得越来越复杂,使得阅读代码变得更加困难。

如何在Elixir中以干净的方式实现相同的任务(通过ab信号触发c事件)?

EN

回答 2

Stack Overflow用户

发布于 2019-09-16 08:32:31

这真的取决于你的用例。但这里有一个可能的解决方案。

您可以使用:gen_event发出ab的信号。然后,您可以让一些GenServer负责操作c侦听发出的事件。一旦您的GenServer收到关于ab正在完成的两条消息,您就可以执行c操作了。您的代码将如下所示。

代码语言:javascript
运行
复制
defmodule EventTest.EventManager do
  def notify(event) do
    :gen_event.notify(__MODULE__, event)
  end

  def register(ref) do
    :gen_event.add_handler(__MODULE__, ref, [])
  end
end

defmodule EventTest.EventConsumer do
  @behaviour :gen_event

  def init(_) do
    state = %{
      a: false,
      b: false
    }

    {:ok, state}
  end

  def maybe_c(%{a: true, b: true}) do
    # Do the thing
    IO.puts "C COMPLETED!"
  end
  def maybe_c(_), do: nil

  def handle_event(event, state) do
    new_state = %{ state | event => true }

    maybe_c(new_state)

    {:ok, new_state}
  end

  def handle_call(msg, state) do
    IO.inspect msg, label: "Unexpected Message"
    {:ok, :ok, state}
  end
end

然后,在某个地方,您只需要将EventTest.EventConsumer注册到EventTest.EventManager。在按任意顺序调用EventTest.EventManager.notify(:a)EventTest.EventManager.notify(:b)之后,您将看到执行c操作的输出。在这种情况下,它只是打印到屏幕上。

这样做的好处是,如果您需要在某个任意的时间范围内完成ab,以便动作c完成,您可以根据需要发送消息来重置:a:b密钥。

票数 1
EN

Stack Overflow用户

发布于 2019-09-17 02:34:17

另一种解决方案是使用Task.async/1Task.await/2。基本上,您可以独立地启动这两个进程,然后等待它们都完成。

代码语言:javascript
运行
复制
task1 = Task.async(fn () -> Process.sleep(2000) end)
task2 = Task.async(fn () -> Process.sleep(2000) end)
[task1, task2] |> Enum.each(&Task.await(&1))

根据事件的触发方式,您可以使用receive/1进行阻塞,直到事件在另一个进程中发生并发送一条消息。有关发送和接收消息的简单概述,请参阅https://elixir-lang.org/getting-started/processes.html#send-and-receive

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57948654

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档