在Elixir进程完成之前保持chunked连接打开

时间:2016-08-31 16:16:50

标签: multithreading elixir

应用程序很简单。当它收到请求时,它会生成thread_listener并将其循环10次并传递索引(i)。 ndc_thread获取此数据(i)并返回核心。 Core正在循环并等待来自线程的消息,当它收到时,它会发送包含线程返回的消息的块。

问题是,在执行了1..10循环功能之后,它发送"结束"大块并关闭连接。 因此curl http://localhost:4000的输出是:" StartEnd" 期望的结果是:" Start12345678910End"

有没有办法保持连接打开并等到自定义超时或等待进程执行?

defmodule AlivePlug do
  import Plug.Conn

  def init(opts) do
    opts
  end

  def call(conn, _opts) do
    conn = send_chunked(conn, 200)
    chunk(conn, "Start")

    core_pid = spawn_link(fn -> core_listener(conn) end)
    thread = spawn_link(fn -> thread_listener end)
    1..10 |> Enum.each(fn i -> send thread, {core_pid, i} end)

    chunk(conn, "End")
    conn
  end

  defp core_listener(conn) do
    receive do
      {status, i} ->
        _conn = chunk(conn, Integer.to_string(i))
        core_listener(conn)
    end
  end

  defp thread_listener do
    receive do
      {core_pid, i} ->
        send core_pid, {:ok, i}
        thread_listener
      _ ->
        thread_listener
    end
  end
end

这是工作申请 只需运行并使用邮递员或卷曲http://localhost:4000 https://github.com/programisti/keep-alive-elixir

1 个答案:

答案 0 :(得分:1)

好吧,问题是你生成了thread进程,向它发送了一些数据,但是从不等待它有机会工作,然后你持有连接的函数就结束了。

让我们从一个非常幼稚的解决方案开始:

    1..10 |> Enum.each(fn i -> send thread, {core_pid, i} end)
    Process.sleep 5000
    chunk(conn, "End")

如果我们睡了5秒钟,那么thread就应该有足够的时间完成所有工作。这是一个糟糕的解决方案,因为如果你循环到10000然后5秒可能太短而且1..10 5秒可能太长了。而且,你不应该相信盲目的时机。 理论上系统可能会等待30秒一次,再等待10毫秒,以便在CPU上安排thread

现在让我们根据进程邮箱是FIFO的事实做一个真正的解决方案。

首先,我们将添加thread_listener理解的其他类型的消息:

  defp thread_listener do
    receive do
      {core_pid, i} ->
        send core_pid, {:ok, i}
        thread_listener
      {:please_ack, pid} ->
        send pid :ack
        thread_listener
      _ ->
        thread_listener
    end
  end

接下来,让我们用更聪明的东西替换Process.sleep

    1..10 |> Enum.each(fn i -> send thread, {core_pid, i} end)
    send thread, {:please_ack, self}
    receive do
      :ack ->
        ok
    end
    chunk(conn, "End")

现在我们将第11条消息放入thread的邮箱,然后等待确认。一旦处理了所有11条消息,我们将收到一条消息并能够继续。如果thread处理每个消息的时间或者在它开始之前是否有10秒的暂停,则无关紧要。 (这些数字是双曲线的,但我试图强调,在多线程编程中,你不能依赖于时序。)

您现在可能已经注意到,我们实施的内容实际上并没有以有用的方式使用流程。你从主线程中产生了两个线程,它们都处于空闲状态,直到主线程向它们发送数据,然后你的线程处于空闲状态,直到产生的线程完成为止。在主线程中完成工作会更清楚。这个例子实际上需要线程太简单了,我无法发现你计划如何扩展它,但我希望这给你一些关于线程编程的一般帮助。