檢視原始碼 程序 (Elixir v1.16.2)
與程序和程序字典搭配使用的便利功能。
除了此模組中提供的功能外,Kernel
模組會公開並自動匯入一些與程序相關的基本功能,可透過下列函式取得
Kernel.spawn/1
和Kernel.spawn/3
Kernel.spawn_link/1
和Kernel.spawn_link/3
Kernel.spawn_monitor/1
和Kernel.spawn_monitor/3
Kernel.self/0
Kernel.send/2
雖然此模組提供低階便利功能來處理程序,但開發人員通常會使用抽象化功能,例如 Agent
、GenServer
、Registry
、Supervisor
和 Task
來建置系統,並使用此模組來收集資訊、捕捉退出、連結和監控。
別名
別名是 Erlang/OTP 24 中引入的功能。別名是一種用於參照 PID 以向其傳送訊息的方式。使用別名的優點是,即使別名程序仍在執行,也可以停用別名。如果您傳送訊息至已停用的別名,則不會發生任何事。這使得請求/回應情境更容易實作。
您可以使用 alias/0
或 alias/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 參考手冊 的 程序別名區段。
摘要
函式
建立程序別名。
建立程序別名。
判斷給定的程序是否在本地節點上執行中。
取消由 send_after/3
傳回的計時器。
從程序字典中刪除給定的 key
。
取消由給定的 reference
識別的監視器。
傳送結束訊號,其中包含給定的 reason
,至 pid
。
將給定的 flag
設定為呼叫程序的 value
。
將給定的 flag
設定為給定程序 pid
的 value
。
傳回程序字典中的所有鍵值配對。
傳回程序字典中給定 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
毫秒後,傳送 msg
至 dest
。
讓目前的程序休眠給定的 timeout
。
根據給定的選項,執行給定的函數。
執行模組 mod
中的給定函數 fun
,根據給定的選項傳遞給定的 args
。
明確停用程序別名。
移除呼叫程序與給定項目(程序或埠)之間的連結。
移除與 PID 或埠識別碼關聯的已註冊 name
。
傳回在 name
下註冊的 PID 或埠識別碼,如果名稱未註冊,則傳回 nil
。
類型
@type alias() :: reference()
更多關於別名的資訊,請參閱 模組文件。
@type alias_opt() :: :explicit_unalias | :reply
程序目的地。
遠端或本機 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()]
函數
@spec alias() :: alias()
建立程序別名。
這與呼叫 alias/1
為 alias([:explicit_unalias])
相同。另請參閱 :erlang.alias/0
。
由編譯器內嵌。
範例
alias = Process.alias()
建立程序別名。
有關別名的更多資訊,請參閱 模組文件。另請參閱 :erlang.alias/1
。
由編譯器內嵌。
範例
alias = Process.alias([:reply])
判斷給定的程序是否在本地節點上執行中。
如果 pid
所識別的程序是運作中的(亦即,它尚未結束且尚未退出),則此函式會傳回 true
。否則,它會傳回 false
。
pid
必須是指在本地節點上執行的程序,否則會引發 ArgumentError
。
由編譯器內嵌。
@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
且:info
為true
時,會傳回整數或false
(如上所述)。如果:async
為false
且:info
為false
,則會傳回:ok
。如果:async
為true
且:info
為true
,則會在執行取消時將格式為{:cancel_timer, timer_ref, result}
的訊息(其中result
是整數或false
,如上所述)傳送給此函式的呼叫者。如果:async
為true
且:info
為false
,則不會傳送訊息。預設為true
。
從程序字典中刪除給定的 key
。
傳回程序字典中 key
下的值,如果 key
未儲存在程序字典中,則傳回 nil
。
範例
iex> Process.put(:comments, ["comment", "other comment"])
iex> Process.delete(:comments)
["comment", "other comment"]
iex> Process.delete(:comments)
nil
取消由給定的 reference
識別的監視器。
如果 monitor_ref
是呼叫程序透過呼叫 monitor/1
取得的參考,則會關閉監控。如果監控已經關閉,則不會發生任何事。
請參閱 :erlang.demonitor/2
以取得更多資訊。
由編譯器內嵌。
範例
pid = spawn(fn -> 1 + 2 end)
ref = Process.monitor(pid)
Process.demonitor(ref)
#=> true
傳送結束訊號,其中包含給定的 reason
,至 pid
。
如果 reason
是 :normal
或 :kill
以外的任何項目,則套用下列行為
如果
pid
沒有攔截退出,則pid
會以指定的reason
退出。如果
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
設定為給定程序 pid
的 value
。
傳回 flag
的舊值。
如果 pid
不是本機程序,則會引發 ArgumentError
。
允許的 flag
值僅為 flag/2
中允許值的子集,也就是 :save_calls
。
請參閱 :erlang.process_flag/3
以取得更多資訊。
由編譯器內嵌。
傳回程序字典中的所有鍵值配對。
由編譯器內嵌。
傳回程序字典中給定 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
傳回程序字典中具有給定 value
的所有鍵。
由編譯器內嵌。
@spec group_leader() :: pid()
傳回呼叫程序的群組負責人的 PID。
由編譯器內嵌。
範例
Process.group_leader()
#=> #PID<0.53.0>
將給定 pid
的群組負責人設定為 leader
。
通常,這是用於從特定殼層啟動的程序應具有 :init
以外的群組負責人。
由編譯器內嵌。
將呼叫程序置於「休眠」狀態。
呼叫程序會進入等待狀態,其記憶體配置已盡可能減少,如果程序預期在不久的將來不會收到任何訊息,這會很有用。
請參閱 :erlang.hibernate/3
以取得更多資訊。
由編譯器內嵌。
傳回由 pid
識別的程序資訊,或在程序未執行時傳回 nil
。
僅將此用於偵錯資訊。
請參閱 :erlang.process_info/1
以取得更多資訊。
傳回由 pid
識別的程序資訊,或在程序未執行時傳回 nil
。
有關更多資訊,請參閱 :erlang.process_info/2
。
在呼叫程序與給定的項目(程序或連接埠)之間建立連結。
連結是雙向的。已連結的程序可以使用 unlink/1
取消連結。
如果已存在此類連結,則此函式不會執行任何動作,因為兩個給定的程序之間只能有一個連結。如果程序嘗試建立連結到自身,則不會發生任何事。
當兩個程序連結時,每個程序都會接收來自另一個程序的退出訊號(另請參閱 exit/2
)。假設 pid1
和 pid2
已連結。如果 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>, ...]
開始從呼叫程序監視給定的 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}
@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}
將給定的 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
從未對應到任何計時器。
即使計時器已過期且訊息已傳送,此函式也不會告訴你逾時訊息是否已傳達到目的地。
由編譯器內嵌。
在本地節點上,使用給定的 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
@spec send_after(pid() | atom(), term(), non_neg_integer(), [option]) :: reference() when option: {:abs, boolean()}
在 time
毫秒後,傳送 msg
至 dest
。
如果 dest
是 PID,它必須是本機程序的 PID,無論程序是否存活。如果 dest
是原子,它必須是已註冊程序的名稱,並在傳送時查詢。如果名稱未指向程序,不會產生錯誤。
訊息不會立即傳送。因此,即使 time
為 0
,dest
仍可以在其間接收其他訊息。
此函式會傳回計時器參考,可以使用 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/1
和 Task.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>
執行模組 mod
中的給定函數 fun
,根據給定的選項傳遞給定的 args
。
結果取決於給定的選項。特別是,如果 :monitor
作為選項給出,它將傳回包含 PID 和監控參考的元組,否則僅傳回已產生程序的 PID。
它也接受額外選項,如需可用選項的清單,請查看 :erlang.spawn_opt/4
。
由編譯器內嵌。
明確停用程序別名。
如果 alias
是目前程序的目前活動別名,則傳回 true
,否則傳回 false
。
請參閱 模組文件 以取得有關別名的更多資訊。另請參閱 :erlang.unalias/1
。
由編譯器內嵌。
範例
alias = Process.alias()
Process.unalias(alias)
#=> 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
傳回在 name
下註冊的 PID 或埠識別碼,如果名稱未註冊,則傳回 nil
。
請參閱 :erlang.whereis/1
以取得更多資訊。
範例
Process.register(self(), :test)
Process.whereis(:test)
#=> #PID<0.84.0>
Process.whereis(:wrong_name)
#=> nil