如何为File.stream创建分散的引用?

时间:2017-02-13 15:17:00

标签: elixir

通常在创建流后,人们会运行流来开始流式传输!听起来很直接。

像:

File.stream!(path)
|> Stream.run

但是,我怎么能推迟运行流直到我需要运行它?我能看到的唯一方法是在分散的引用中注册流,稍后使用引用来运行流。

这甚至可能吗?如何?

修改 这是我想要做的: enter image description here

2 个答案:

答案 0 :(得分:0)

File.Stream!返回一个值,您可以根据需要存储和运行多次。流在Elixir中实现为功能的组合。像这样的东西。

 stream_maps = Map.put(%{}, client_tag, File.Stream!(path) )

稍后,

 stream_maps |> Map.get(client_tag) |> Stream.run 

您可以将其扩展为原始File.Stream中的任何Stream函数组合!

答案 1 :(得分:0)

以下是使用GenServer存储流并运行它们的一种方法:

defmodule StreamStore do
  use GenServer

  def start_link do
    GenServer.start_link(__MODULE__, [])
  end

  def init(_) do
    {:ok, %{map: %{}, next: 0}}
  end

  def put(server, stream) do
    GenServer.call(server, {:store, stream})
  end

  def run(server, key) do
    GenServer.call(server, {:run, key})
  end

  def handle_call({:store, stream}, _from, %{map: map, next: next}) do
    state = %{map: Map.put(map, next, stream), next: next + 1}
    {:reply, next, state}
  end

  def handle_call({:run, key}, _from, %{map: map} = state) do
    # If the key exists, pop and run it, otherwise return `{:error, :badkey}`.
    case Map.pop(map, key) do
      {nil, _} ->
        {:reply, {:error, :badkey}, state}
      {stream, map} ->
        Task.start_link(Stream, :run, [stream])
        {:reply, :ok, %{state | map: map}}
    end
  end
end

{:ok, ss} = StreamStore.start_link

# I'm storing a `Stream.map` over a list here, but you can store file streams as well.
first = StreamStore.put(ss, [1, 2, 3] |> Stream.map(&IO.puts/1))
second = StreamStore.put(ss, [4, 5, 6] |> Stream.map(&IO.puts/1))
third = StreamStore.put(ss, [7, 8, 9] |> Stream.map(&IO.puts/1))

Process.sleep(100)
IO.inspect StreamStore.run(ss, second)
Process.sleep(100)
IO.inspect StreamStore.run(ss, third)
Process.sleep(100)
IO.inspect StreamStore.run(ss, first)
Process.sleep(100)
# The stream has been removed from the store, so this will print `{:error, :badkey}`
IO.inspect StreamStore.run(ss, first)

输出:

:ok
4
5
6
:ok
7
8
9
:ok
1
2
3
{:error, :badkey}

StreamStore.put/2返回一个密钥,稍后可以将该密钥传递给StreamStore.run/2以运行该特定流。我正在使用Task.start_link生成进程并在其中运行流。你可能想在使用它之前调整所有这些,但这应该是一个好的开始。