查看源代码 Process (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 标识的监控器的监控。

pid 发送带有给定 reason 的退出信号。

为调用进程设置给定的 flagvalue

为给定的进程 pid 设置给定的 flagvalue

返回进程字典中的所有键值对。

返回进程字典中给定 key 的值,如果 key 未设置,则返回 default

返回进程字典中的所有键。

返回进程字典中具有给定 value 的所有键。

返回调用进程的组领导者的 PID。

将给定 pid 的组领导者设置为 leader

将调用进程置于“休眠”状态。

返回由 pid 标识的进程的信息,如果进程不存在,则返回 nil

返回由 pid 标识的进程的信息,如果进程不存在,则返回 nil

在调用进程和给定项(进程或端口)之间创建链接。

返回一个 PID 列表,这些 PID 对应于当前在本地节点上存在的所有进程。

从调用进程开始监控给定的 item

从调用进程开始监控给定的 item

在进程字典中存储给定的 key-value 对。

读取由 send_after/3 创建的计时器。

在本地节点上将给定的 pid_or_port 注册到给定的 name 下。

返回使用 register/2 注册的名称列表。

向给定的 dest 发送消息。

time 毫秒后将 msg 发送到 dest

使当前进程休眠给定的 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/1 作为 alias([: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 - (boolean) 当为 false 时,取消请求是同步的。当为 true 时,取消请求是异步的,这意味着发出取消计时器的请求,并立即返回 :ok。默认为 false

  • :info - (boolean) 是否返回有关被取消计时器的信息。当 :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

pid 发送带有给定 reason 的退出信号。

如果 reason 不是 :normal:kill,则将应用以下行为。

  1. 如果 pid 未捕获退出信号,pid 将以指定的 reason 退出。

  2. 如果 pid 捕获了退出信号,则退出信号将被转换为消息 {:EXIT, from, reason} 并传递到 pid 的消息队列中。

如果 reason 是原子 :normal,则 pid 不会退出(除非 pid 是调用进程,在这种情况下它将以 :normal 原因退出)。如果它捕获了退出信号,则退出信号将被转换为消息 {:EXIT, from, :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()

为调用进程设置给定的 flagvalue

返回 flag 的旧值。

有关更多信息,请参阅 :erlang.process_flag/2

由编译器内联。

链接到此函数

flag(pid, flag, value)

查看源代码
@spec flag(pid(), :save_calls, 0..10000) :: 0..10000

为给定的进程 pid 设置给定的 flagvalue

返回 flag 的旧值。

如果 pid 不是本地进程,则会引发 ArgumentError

允许用于 flag 的值只是 flag/2 中允许值的一个子集,即 :save_calls

有关更多信息,请参阅 :erlang.process_flag/3

由编译器内联。

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

返回进程字典中的所有键值对。

由编译器内联。

链接到此函数

get(key, default \\ nil)

查看源代码
@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

通常,这用于当从某个 shell 启动的进程应该拥有一个不同于 :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 列表,这些 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

在本地节点上将给定的 pid_or_port 注册到给定的 name 下。

name 必须是一个原子,然后可以用它代替 PID/端口标识符,使用 Kernel.send/2 发送消息。

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, ...]
链接到此函数

send(dest, msg, options)

查看源代码
@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 毫秒后将 msg 发送到 dest

如果 dest 是一个 PID,它必须是本地进程的 PID,无论存活与否。如果 dest 是一个原子,它必须是注册进程的名称,该名称将在传递时进行查找。如果名称不引用进程,则不会产生错误。

消息不会立即发送。因此,即使 time0dest 也可以在其间接收其他消息。

此函数返回一个计时器引用,可以使用 read_timer/1 读取或使用 cancel_timer/1 取消。

如果给定的 dest 是一个不存在的 PID 或给定的 PID 退出,则计时器将自动取消。请注意,当 dest 是一个原子时,计时器不会自动取消(因为原子解析是在传递时完成的)。

由编译器内联。

选项

  • :abs - (布尔值) 当为 false 时,time 被视为相对于当前单调时间。当为 true 时,timemsg 应该传递到 dest 的 Erlang 单调时间的绝对值。要了解更多有关 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