當前位置: 首頁>>編程示例 >>用法及示例精選 >>正文


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)。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。