檢視原始碼 程序 (Elixir v1.16.2)

與程序和程序字典搭配使用的便利功能。

除了此模組中提供的功能外,Kernel 模組會公開並自動匯入一些與程序相關的基本功能,可透過下列函式取得

雖然此模組提供低階便利功能來處理程序,但開發人員通常會使用抽象化功能,例如 AgentGenServerRegistrySupervisorTask 來建置系統,並使用此模組來收集資訊、捕捉退出、連結和監控。

別名

別名是 Erlang/OTP 24 中引入的功能。別名是一種用於參照 PID 以向其傳送訊息的方式。使用別名的優點是,即使別名程序仍在執行,也可以停用別名。如果您傳送訊息至已停用的別名,則不會發生任何事。這使得請求/回應情境更容易實作。

您可以使用 alias/0alias/1 來設定別名,然後您可以使用 send/2 將訊息傳送至該別名,就像使用 PID 一樣。若要停用別名,您可以使用 unalias/1。如果您傳送訊息至已停用的別名,則不會發生任何事。

例如,您可以有一個偵聽 :ping 訊息的程序

def server do
  receive do
    {:ping, source_alias} ->
      send(source_alias, :pong)
      server()
  end
end

現在,另一個程序可能會 ping 這個程序

server = spawn(&server/0)

source_alias = Process.alias()
send(server, {:ping, source_alias})

receive do
  :pong -> :pong
end
#=> :pong

如果您現在停用 source_alias 並再次 ping 伺服器,您不會收到任何回應,因為伺服器會將 :pong 回應 send/2 至已停用的別名。

Process.unalias(source_alias)
send(server, {:ping, source_alias})

receive do
  :pong -> :pong
after
  1000 -> :timeout
end
#=> :timeout

另請參閱 Erlang 參考手冊程序別名區段

摘要

類型

alias/0alias/1 傳回的別名。

程序目的地。

函式

建立程序別名。

建立程序別名。

判斷給定的程序是否在本地節點上執行中。

取消由 send_after/3 傳回的計時器。

從程序字典中刪除給定的 key

取消由給定的 reference 識別的監視器。

傳送結束訊號,其中包含給定的 reason,至 pid

將給定的 flag 設定為呼叫程序的 value

將給定的 flag 設定為給定程序 pidvalue

傳回程序字典中的所有鍵值配對。

傳回程序字典中給定 key 的值,或在 key 未設定時傳回 default

傳回程序字典中的所有鍵。

傳回程序字典中具有給定 value 的所有鍵。

傳回呼叫程序的群組負責人的 PID。

將給定 pid 的群組負責人設定為 leader

將呼叫程序置於「休眠」狀態。

傳回由 pid 識別的程序資訊,或在程序未執行時傳回 nil

傳回由 pid 識別的程序資訊,或在程序未執行時傳回 nil

在呼叫程序與給定的項目(程序或連接埠)之間建立連結。

傳回目前在本地節點上執行所有程序的 PID 清單。

開始從呼叫程序監視給定的 item

開始從呼叫程序監視給定的 item

將給定的 key-value 對儲存在程序字典中。

讀取由 send_after/3 建立的計時器。

在本地節點上,使用給定的 name 註冊給定的 pid_or_port

傳回使用 register/2 註冊的名稱清單。

傳送訊息至給定的 dest

time 毫秒後,傳送 msgdest

讓目前的程序休眠給定的 timeout

根據給定的選項,執行給定的函數。

執行模組 mod 中的給定函數 fun,根據給定的選項傳遞給定的 args

明確停用程序別名。

移除呼叫程序與給定項目(程序或埠)之間的連結。

移除與 PID 或埠識別碼關聯的已註冊 name

傳回在 name 下註冊的 PID 或埠識別碼,如果名稱未註冊,則傳回 nil

類型

@type alias() :: reference()

alias/0alias/1 傳回的別名。

更多關於別名的資訊,請參閱 模組文件

@type alias_opt() :: :explicit_unalias | :reply
@type dest() ::
  pid()
  | port()
  | (registered_name :: atom())
  | {registered_name :: atom(), node()}

程序目的地。

遠端或本機 PID、本機埠、本機註冊的名稱,或以 {registered_name, node} 形式表示的元組,用於另一個節點上的註冊名稱。

@type spawn_opt() ::
  :link
  | :monitor
  | {:monitor, :erlang.monitor_option()}
  | {:priority, :low | :normal | :high}
  | {:fullsweep_after, non_neg_integer()}
  | {:min_heap_size, non_neg_integer()}
  | {:min_bin_vheap_size, non_neg_integer()}
  | {:max_heap_size, heap_size()}
  | {:message_queue_data, :off_heap | :on_heap}
@type spawn_opts() :: [spawn_opt()]

函數

連結到此函數

alias()

檢視原始碼 (自 1.15.0 起)
@spec alias() :: alias()

建立程序別名。

這與呼叫 alias/1alias([:explicit_unalias]) 相同。另請參閱 :erlang.alias/0

由編譯器內嵌。

範例

alias = Process.alias()
連結到此函數

alias(options)

檢視原始碼 (自 1.15.0 起)
@spec alias([alias_opt()]) :: alias()

建立程序別名。

有關別名的更多資訊,請參閱 模組文件。另請參閱 :erlang.alias/1

由編譯器內嵌。

範例

alias = Process.alias([:reply])
@spec alive?(pid()) :: boolean()

判斷給定的程序是否在本地節點上執行中。

如果 pid 所識別的程序是運作中的(亦即,它尚未結束且尚未退出),則此函式會傳回 true。否則,它會傳回 false

pid 必須是指在本地節點上執行的程序,否則會引發 ArgumentError

由編譯器內嵌。

連結到此函數

cancel_timer(timer_ref, options \\ [])

檢視原始碼
@spec cancel_timer(reference(), options) :: non_neg_integer() | false | :ok
when options: [async: boolean(), info: boolean()]

取消由 send_after/3 傳回的計時器。

當結果是整數時,它代表計時器過期前剩餘的毫秒數。

當結果為 false 時,找不到與 timer_ref 相應的計時器。這可能是因為計時器已過期、已取消或 timer_ref 從未對應到任何計時器。

即使計時器已過期且訊息已傳送,此函式也不會告訴你逾時訊息是否已傳達到目的地。

由編譯器內嵌。

選項

  • :async -(布林值)當為 false 時,取消請求是同步的。當為 true 時,取消請求是異步的,表示已發出取消計時器的請求,並立即傳回 :ok。預設為 false

  • :info -(布林值)是否傳回有關正在取消的計時器的資訊。當 :async 選項為 false:infotrue 時,會傳回整數或 false(如上所述)。如果 :asyncfalse:infofalse,則會傳回 :ok。如果 :asynctrue:infotrue,則會在執行取消時將格式為 {:cancel_timer, timer_ref, result} 的訊息(其中 result 是整數或 false,如上所述)傳送給此函式的呼叫者。如果 :asynctrue:infofalse,則不會傳送訊息。預設為 true

@spec delete(term()) :: term() | nil

從程序字典中刪除給定的 key

傳回程序字典中 key 下的值,如果 key 未儲存在程序字典中,則傳回 nil

範例

iex> Process.put(:comments, ["comment", "other comment"])
iex> Process.delete(:comments)
["comment", "other comment"]
iex> Process.delete(:comments)
nil
連結到此函數

demonitor(monitor_ref, options \\ [])

檢視原始碼
@spec demonitor(reference(), options :: [:flush | :info]) :: boolean()

取消由給定的 reference 識別的監視器。

如果 monitor_ref 是呼叫程序透過呼叫 monitor/1 取得的參考,則會關閉監控。如果監控已經關閉,則不會發生任何事。

請參閱 :erlang.demonitor/2 以取得更多資訊。

由編譯器內嵌。

範例

pid = spawn(fn -> 1 + 2 end)
ref = Process.monitor(pid)
Process.demonitor(ref)
#=> true
@spec exit(pid(), term()) :: true

傳送結束訊號,其中包含給定的 reason,至 pid

如果 reason:normal:kill 以外的任何項目,則套用下列行為

  1. 如果 pid 沒有攔截退出,則 pid 會以指定的 reason 退出。

  2. 如果 pid 有攔截退出,則退出訊號會轉換成訊息 {:EXIT, from, reason} 並傳遞到 pid 的訊息佇列。

如果 reason 是原子 :normal,則 pid 不會退出(除非 pid 是呼叫程序,這種情況下它會以原因 :normal 退出)。如果它有攔截退出,則退出訊號會轉換成訊息 reason 是原子 :kill,也就是如果呼叫 Process.exit(pid, :kill),則會傳送無法攔截的退出訊號到 pid,它會無條件以原因 :killed 退出。

由編譯器內嵌。

範例

Process.exit(pid, :kill)
#=> true
@spec flag(:error_handler, module()) :: module()
@spec flag(:max_heap_size, heap_size()) :: heap_size()
@spec flag(:message_queue_data, :off_heap | :on_heap) :: :off_heap | :on_heap
@spec flag(:min_bin_vheap_size, non_neg_integer()) :: non_neg_integer()
@spec flag(:min_heap_size, non_neg_integer()) :: non_neg_integer()
@spec flag(:priority, priority_level()) :: priority_level()
@spec flag(:save_calls, 0..10000) :: 0..10000
@spec flag(:sensitive, boolean()) :: boolean()
@spec flag(:trap_exit, boolean()) :: boolean()

將給定的 flag 設定為呼叫程序的 value

傳回 flag 的舊值。

請參閱 :erlang.process_flag/2 以取得更多資訊。

由編譯器內嵌。

@spec flag(pid(), :save_calls, 0..10000) :: 0..10000

將給定的 flag 設定為給定程序 pidvalue

傳回 flag 的舊值。

如果 pid 不是本機程序,則會引發 ArgumentError

允許的 flag 值僅為 flag/2 中允許值的子集,也就是 :save_calls

請參閱 :erlang.process_flag/3 以取得更多資訊。

由編譯器內嵌。

@spec get() :: [{term(), term()}]

傳回程序字典中的所有鍵值配對。

由編譯器內嵌。

@spec get(term(), default :: term()) :: term()

傳回程序字典中給定 key 的值,或在 key 未設定時傳回 default

範例

# Assuming :locale was not set
iex> Process.get(:locale, "pt")
"pt"
iex> Process.put(:locale, "fr")
nil
iex> Process.get(:locale, "pt")
"fr"
@spec get_keys() :: [term()]

傳回程序字典中的所有鍵。

由編譯器內嵌。

範例

# Assuming :locale was not set
iex> :locale in Process.get_keys()
false
iex> Process.put(:locale, "pt")
nil
iex> :locale in Process.get_keys()
true
@spec get_keys(term()) :: [term()]

傳回程序字典中具有給定 value 的所有鍵。

由編譯器內嵌。

@spec group_leader() :: pid()

傳回呼叫程序的群組負責人的 PID。

由編譯器內嵌。

範例

Process.group_leader()
#=> #PID<0.53.0>
連結到此函數

group_leader(pid, leader)

檢視原始碼
@spec group_leader(pid(), leader :: pid()) :: true

將給定 pid 的群組負責人設定為 leader

通常,這是用於從特定殼層啟動的程序應具有 :init 以外的群組負責人。

由編譯器內嵌。

連結到此函數

hibernate(mod, fun_name, args)

檢視原始碼
@spec hibernate(module(), atom(), list()) :: no_return()

將呼叫程序置於「休眠」狀態。

呼叫程序會進入等待狀態,其記憶體配置已盡可能減少,如果程序預期在不久的將來不會收到任何訊息,這會很有用。

請參閱 :erlang.hibernate/3 以取得更多資訊。

由編譯器內嵌。

@spec info(pid()) :: keyword() | nil

傳回由 pid 識別的程序資訊,或在程序未執行時傳回 nil

僅將此用於偵錯資訊。

請參閱 :erlang.process_info/1 以取得更多資訊。

@spec info(pid(), atom() | [atom()]) :: {atom(), term()} | [{atom(), term()}] | nil

傳回由 pid 識別的程序資訊,或在程序未執行時傳回 nil

有關更多資訊,請參閱 :erlang.process_info/2

@spec link(pid() | port()) :: true

在呼叫程序與給定的項目(程序或連接埠)之間建立連結。

連結是雙向的。已連結的程序可以使用 unlink/1 取消連結。

如果已存在此類連結,則此函式不會執行任何動作,因為兩個給定的程序之間只能有一個連結。如果程序嘗試建立連結到自身,則不會發生任何事。

當兩個程序連結時,每個程序都會接收來自另一個程序的退出訊號(另請參閱 exit/2)。假設 pid1pid2 已連結。如果 pid2 退出,原因不是 :normal(這也是程序完成工作時使用的退出原因),而且 pid1 沒有攔截退出(請參閱 flag/2),則 pid1 會以與 pid2 相同的原因退出,並向其所有其他連結的程序發出退出訊號。當 pid1 攔截退出時,其行為說明於 exit/2 中。

有關更多資訊,請參閱 :erlang.link/1

由編譯器內嵌。

@spec list() :: [pid()]

傳回目前在本地節點上執行所有程序的 PID 清單。

請注意,如果程序正在退出,則視為存在但未執行中。這表示對於此類程序,alive?/1 會傳回 false,但其 PID 會是此函式傳回的 PID 清單的一部分。

有關更多資訊,請參閱 :erlang.processes/0

由編譯器內嵌。

範例

Process.list()
#=> [#PID<0.0.0>, #PID<0.1.0>, #PID<0.2.0>, #PID<0.3.0>, ...]
@spec monitor(pid() | {name, node()} | name) :: reference() when name: atom()

開始從呼叫程序監視給定的 item

受監視程序死亡後,會傳送訊息給監視程序,格式如下

{:DOWN, ref, :process, object, reason}

其中

  • ref 是此函式傳回的監視參考;
  • object 是受監視程序的 pid(如果監視 PID)或 {name, node}(如果監視遠端或本機名稱);
  • reason 是退出原因。

如果呼叫 Process.monitor/1 時,程序已死亡,則會立即傳送 :DOWN 訊息。

請參閱 「監控需求」 以取得範例。請參閱 :erlang.monitor/2 以取得更多資訊。

由編譯器內嵌。

範例

pid = spawn(fn -> 1 + 2 end)
#=> #PID<0.118.0>
Process.monitor(pid)
#=> #Reference<0.906660723.3006791681.40191>
Process.exit(pid, :kill)
#=> true
receive do
  msg -> msg
end
#=> {:DOWN, #Reference<0.906660723.3006791681.40191>, :process, #PID<0.118.0>, :noproc}
連結到此函數

monitor(item, options)

檢視原始碼 (自 1.15.0 起)
@spec monitor(pid() | {name, node()} | name, [:erlang.monitor_option()]) ::
  reference()
when name: atom()

開始從呼叫程序監視給定的 item

此函式類似於 monitor/1,但接受選項以自訂 item 的監控方式。請參閱 :erlang.monitor/3 以取得這些選項的說明文件。

由編譯器內嵌。

範例

pid =
  spawn(fn ->
    receive do
      {:ping, source_alias} -> send(source_alias, :pong)
    end
  end)
#=> #PID<0.118.0>

ref_and_alias = Process.monitor(pid, alias: :reply_demonitor)
#=> #Reference<0.906660723.3006791681.40191>

send(pid, {:ping, ref_and_alias})

receive do: msg -> msg
#=> :pong

receive do: msg -> msg
#=> {:DOWN, #Reference<0.906660723.3006791681.40191>, :process, #PID<0.118.0>, :noproc}
@spec put(term(), term()) :: term() | nil

將給定的 key-value 對儲存在程序字典中。

此函式的傳回值為先前儲存在 key 下的值,或 nil(若未在其中儲存任何值)。

範例

# Assuming :locale was not set
iex> Process.put(:locale, "en")
nil
iex> Process.put(:locale, "fr")
"en"
@spec read_timer(reference()) :: non_neg_integer() | false

讀取由 send_after/3 建立的計時器。

當結果為整數時,代表計時器到期前剩餘的毫秒數。

當結果為 false 時,找不到與 timer_ref 相應的計時器。原因可能是計時器已到期、已取消,或 timer_ref 從未對應到任何計時器。

即使計時器已過期且訊息已傳送,此函式也不會告訴你逾時訊息是否已傳達到目的地。

由編譯器內嵌。

連結到此函數

register(pid_or_port, name)

檢視原始碼
@spec register(pid() | port(), atom()) :: true

在本地節點上,使用給定的 name 註冊給定的 pid_or_port

name 必須為原子,然後可以在使用 Kernel.send/2 傳送訊息時,取代 PID/埠識別碼。

register/2 會在下列任何情況下失敗,並顯示 ArgumentError

  • PID/埠在本地不存在且未啟動
  • 名稱已註冊
  • pid_or_port 已在不同的 name 下註冊

下列名稱已保留,無法指定給程序或埠

  • nil
  • false
  • true
  • :undefined

範例

Process.register(self(), :test)
#=> true
send(:test, :hello)
#=> :hello
send(:wrong_name, :hello)
** (ArgumentError) argument error
@spec registered() :: [atom()]

傳回使用 register/2 註冊的名稱清單。

由編譯器內嵌。

範例

Process.register(self(), :test)
Process.registered()
#=> [:test, :elixir_config, :inet_db, ...]
@spec send(dest, msg, [option]) :: :ok | :noconnect | :nosuspend
when dest: dest(), msg: any(), option: :noconnect | :nosuspend

傳送訊息至給定的 dest

dest 可以是遠端或本機 PID、本機埠、已在本機註冊的名稱,或 {registered_name, node} 格式的組元,表示另一個節點上的已註冊名稱。

由編譯器內嵌。

選項

  • :noconnect - 使用時,如果傳送訊息需要自動連線到另一個節點,訊息不會傳送,並傳回 :noconnect

  • :nosuspend - 使用時,如果傳送訊息會導致傳送者暫停,訊息不會傳送,並傳回 :nosuspend

否則,訊息會傳送,並傳回 :ok

範例

iex> Process.send({:name, :node_that_does_not_exist}, :hi, [:noconnect])
:noconnect
連結到此函數

send_after(dest, msg, time, opts \\ [])

檢視原始碼
@spec send_after(pid() | atom(), term(), non_neg_integer(), [option]) :: reference()
when option: {:abs, boolean()}

time 毫秒後,傳送 msgdest

如果 dest 是 PID,它必須是本機程序的 PID,無論程序是否存活。如果 dest 是原子,它必須是已註冊程序的名稱,並在傳送時查詢。如果名稱未指向程序,不會產生錯誤。

訊息不會立即傳送。因此,即使 time0dest 仍可以在其間接收其他訊息。

此函式會傳回計時器參考,可以使用 read_timer/1 讀取,或使用 cancel_timer/1 取消。

如果指定的 dest 是不存在的 PID,或當指定的 PID 結束時,計時器會自動取消。請注意,當 dest 是原子時,計時器不會自動取消(因為原子解析是在傳送時進行)。

由編譯器內嵌。

選項

  • :abs -(布林)當 false 時,time 會視為相對於目前單調時間。當 true 時,time 是 Erlang 單調時間的絕對值,msg 會在該時間傳送給 dest。若要進一步了解 Erlang 單調時間和其他與時間相關的概念,請參閱 System 模組的說明文件。預設為 false

範例

timer_ref = Process.send_after(pid, :hi, 1000)
@spec sleep(timeout()) :: :ok

讓目前的程序休眠給定的 timeout

timeout 是以整數表示的睡眠時間(毫秒),或原子 :infinity。當指定 :infinity 時,目前程序會永遠睡眠,且不會使用或回覆訊息。

極為小心地使用此函數。在 Elixir 中,幾乎所有您會使用 sleep/1 的情況,都可能有一個更正確、更快速、更精確的方式,可以使用訊息傳遞來達成相同目的。

例如,如果您正在等待某個程序執行某個動作,最好使用訊息來傳達該動作的進度。

換句話說,不要

Task.start_link(fn ->
  do_something()
  ...
end)

# Wait until work is done
Process.sleep(2000)

而是

parent = self()

Task.start_link(fn ->
  do_something()
  send(parent, :work_is_done)
  ...
end)

receive do
  :work_is_done -> :ok
after
  # Optional timeout
  30_000 -> :timeout
end

對於上述情況,建議使用 Task.async/1Task.await/2

同樣地,如果您正在等待某個程序終止,請監控該程序,而不是讓它進入休眠狀態。不要

Task.start_link(fn ->
  ...
end)

# Wait until task terminates
Process.sleep(2000)

而是這樣做

{:ok, pid} =
  Task.start_link(fn ->
    ...
  end)

ref = Process.monitor(pid)

receive do
  {:DOWN, ^ref, _, _, _} -> :task_is_down
after
  # Optional timeout
  30_000 -> :timeout
end
@spec spawn((-> any()), spawn_opts()) :: pid() | {pid(), reference()}

根據給定的選項,執行給定的函數。

結果取決於給定的選項。特別是,如果 :monitor 作為選項給出,它將傳回包含 PID 和監控參考的元組,否則僅傳回已產生程序的 PID。

有更多選項可用;如需可用選項的完整清單,請查看 :erlang.spawn_opt/4

由編譯器內嵌。

範例

Process.spawn(fn -> 1 + 2 end, [:monitor])
#=> {#PID<0.93.0>, #Reference<0.18808174.1939079169.202418>}
Process.spawn(fn -> 1 + 2 end, [:link])
#=> #PID<0.95.0>
連結到此函數

spawn(mod, fun, args, opts)

檢視原始碼
@spec spawn(module(), atom(), list(), spawn_opts()) :: pid() | {pid(), reference()}

執行模組 mod 中的給定函數 fun,根據給定的選項傳遞給定的 args

結果取決於給定的選項。特別是,如果 :monitor 作為選項給出,它將傳回包含 PID 和監控參考的元組,否則僅傳回已產生程序的 PID。

它也接受額外選項,如需可用選項的清單,請查看 :erlang.spawn_opt/4

由編譯器內嵌。

連結到此函數

unalias(alias)

檢視原始碼 (自 1.15.0 起)
@spec unalias(alias()) :: boolean()

明確停用程序別名。

如果 alias 是目前程序的目前活動別名,則傳回 true,否則傳回 false

請參閱 模組文件 以取得有關別名的更多資訊。另請參閱 :erlang.unalias/1

由編譯器內嵌。

範例

alias = Process.alias()
Process.unalias(alias)
#=> true
@spec unlink(pid() | port()) :: true

移除呼叫程序與給定項目(程序或埠)之間的連結。

如果沒有此連結,此函數不會執行任何操作。如果 pid_or_port 不存在,此函數不會產生任何錯誤,也不會執行任何操作。

此函數的傳回值永遠是 true

請參閱 :erlang.unlink/1 以取得更多資訊。

由編譯器內嵌。

@spec unregister(atom()) :: true

移除與 PID 或埠識別碼關聯的已註冊 name

如果名稱未註冊到任何 PID 或埠,則會傳回 ArgumentError 錯誤。

由編譯器內嵌。

範例

Process.register(self(), :test)
#=> true
Process.unregister(:test)
#=> true
Process.unregister(:wrong_name)
** (ArgumentError) argument error
@spec whereis(atom()) :: pid() | port() | nil

傳回在 name 下註冊的 PID 或埠識別碼,如果名稱未註冊,則傳回 nil

請參閱 :erlang.whereis/1 以取得更多資訊。

範例

Process.register(self(), :test)
Process.whereis(:test)
#=> #PID<0.84.0>
Process.whereis(:wrong_name)
#=> nil