当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Elixir Task.await用法及代码示例


Elixir语言中 Task.await 相关用法介绍如下。

用法:

await(task, timeout \\ 5000)
@spec await(t(), timeout()) :: term()

等待任务回复并将其返回。

如果任务进程死亡,调用者进程将以与任务相同的原因退出。

超时,以毫秒或 :infinity 为单位,可以使用默认值 5000 给出。如果超时,则调用者进程将退出。如果任务进程链接到调用者进程(即使用 async 启动任务时的情况),则任务进程也将退出。如果任务进程正在捕获退出或未链接到调用者进程,那么它将继续运行。

此函数假定任务的监视器仍处于活动状态或监视器的:DOWN 消息在消息队列中。如果它已经被监控,或者消息已经收到,这个函数将等待等待消息的超时时间。

对于任何给定的任务,此函数只能调用一次。如果您希望能够多次检查 long-running 任务是否已完成其计算,请改用 yield/2

例子

iex> task = Task.async(fn -> 1 + 1 end)
iex> Task.await(task)
2

与 OTP 行为的兼容性

不建议在诸如 GenServer 之类的 OTP 行为中使用 await long-running 任务。相反,您应该匹配来自 GenServer.handle_info/2 回调中的任务的消息。

GenServer 将在 handle_info/2 上收到两条消息:

  • {ref, result} - 回复消息,其中reftask.ref 返回的监视器引用,result 是任务结果

  • {:DOWN, ref, :process, pid, reason} - 由于所有任务也受到监控,您还将收到 Process.monitor/1 传递的 :DOWN 消息。如果您收到:DOWN 消息而没有回复,则表示任务崩溃

要记住的另一个考虑因子是,由 Task.async/1 启动的任务始终链接到它们的调用者,如果任务崩溃,您可能不希望GenServer 崩溃。因此,最好在 OTP 行为中使用 Task.Supervisor.async_nolink/3 。为了完整起见,下面是一个 GenServer 示例,它启动任务并处理其结果:

defmodule GenServerTaskExample do
  use GenServer

  def start_link(opts) do
    GenServer.start_link(__MODULE__, :ok, opts)
  end

  def init(_opts) do
    # We will keep all running tasks in a map
    {:ok, %{tasks: %{}}}
  end

  # Imagine we invoke a task from the GenServer to access a URL...
  def handle_call(:some_message, _from, state) do
    url = ...
    task = Task.Supervisor.async_nolink(MyApp.TaskSupervisor, fn -> fetch_url(url) end)

    # After we start the task, we store its reference and the url it is fetching
    state = put_in(state.tasks[task.ref], url)

    {:reply, :ok, state}
  end

  # If the task succeeds...
  def handle_info({ref, result}, state) do
    # The task succeed so we can cancel the monitoring and discard the DOWN message
    Process.demonitor(ref, [:flush])

    {url, state} = pop_in(state.tasks[ref])
    IO.puts "Got #{inspect(result)} for URL #{inspect url}"
    {:noreply, state}
  end

  # If the task fails...
  def handle_info({:DOWN, ref, _, _, reason}, state) do
    {url, state} = pop_in(state.tasks[ref])
    IO.puts "URL #{inspect url} failed with reason #{inspect(reason)}"
    {:noreply, state}
  end
end

定义了服务器后,您将需要启动上面的任务主管和监督树中的GenServer:

children = [
  {Task.Supervisor, name: MyApp.TaskSupervisor},
  {GenServerTaskExample, name: MyApp.GenServerTaskExample}
]

Supervisor.start_link(children, strategy: :one_for_one)

相关用法


注:本文由纯净天空筛选整理自elixir-lang.org大神的英文原创作品 Task.await(task, timeout \\ 5000)。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。