通常在创建流后,人们会运行流来开始流式传输!听起来很直接。
像:
File.stream!(path)
|> Stream.run
但是,我怎么能推迟运行流直到我需要运行它?我能看到的唯一方法是在分散的引用中注册流,稍后使用引用来运行流。
这甚至可能吗?如何?
答案 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
生成进程并在其中运行流。你可能想在使用它之前调整所有这些,但这应该是一个好的开始。