代码之家  ›  专栏  ›  技术社区  ›  ceremcem

如何编写灵丹妙药中的多事件驱动IF子句?

  •  0
  • ceremcem  · 技术社区  · 6 年前

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

    想一个案子 c 取决于两个变量 a b . 我们的代码应该是这样(在Javascript中):

    if (a && b){
      c();
    }
    

    如果 由一个不同的事件设置,则代码变得稍微复杂一点:

    on('a', function(a){
      if (a && b){
        c();
      }
    });
    

    如果两者都是 是由两个截然不同的事件设定的,事情变得更加复杂。一种解决方案可能是使用 signal 图书馆:

    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 )

    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();
    });
    
    

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

    同一个任务(触发 c类 事件依据 信号在灵丹妙药中以清洁的方式实施?

    0 回复  |  直到 6 年前
        1
  •  1
  •   Justin Wood Yu Hao    6 年前

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

    你可以用 :gen_event 发出信号 a b . 你可以吃点 GenServer 对行动负责的人 c 听发射的事件。一旦你 发电机 接收两条关于 完成后,您可以执行您的操作 c类 . 您的代码如下所示。

    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类 行动。在这种情况下,它只是打印到屏幕上。

    如果你需要完成 在任意的时间范围内采取行动 c类 若要完成,您可以向自己发送消息以重置 :a :b 根据需要提供钥匙。

        2
  •  0
  •   Brett Hazen    6 年前

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

    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 对于发送和接收消息的简单概述。