Clause
← Toda la documentación

Traducido del original en inglés · 1e3a39c8-dirty · 2026-10-26 · Leer en inglés

Procesos

Ejecutor

Un runtime ejecuta sus procesos en sus hilos de trabajo del planificador (hilos de trabajo, modelo de ejecución). El arranque convierte la llamada a la función de entrada en el primer proceso, el proceso principal, y ejecuta el ejecutor hasta que este termina:

Hilos de trabajo

El ejecutor ejecuta los procesos en RuntimeOptions::schedulers hilos de trabajo: el hilo que arrancó el programa y un hilo más por cada hilo de trabajo adicional. Los programas toman el número de --schedulers N (de 1 a 1.024, opciones del runtime); por defecto hay un hilo de trabajo por procesador lógico en el que el programa puede ejecutarse (su máscara de afinidad, como los planificadores en línea de OTP), o por CPU de --scheduler-cpus.

Los despertares y el apagado no necesitan ningún mecanismo adicional, porque todo cambio del estado de planificación de un proceso ocurre bajo el mutex del ejecutor:

Afinidad de CPU

Por defecto, los hilos de trabajo no están vinculados: el SO los sitúa en cualquier CPU de la máscara de afinidad del programa, como el valor por defecto +sbt u de OTP. --scheduler-cpus SET (opciones del runtime) vincula el hilo de trabajo N a la CPU N del conjunto, por turnos cuando hay más hilos de trabajo, como +sbt/+sct de OTP; los hilos de temporizadores y de E/S siguen sin vincularse.

Tiempos de espera de receive

Los temporizadores viven en una rueda de temporizadores jerárquica con hash (timer wheel), como los mantiene ERTS (scheduler/timer_wheel):

Salidas

Un proceso distinto del principal termina con una razón de salida, como en OTP (detail::exit_reason, process/exits). Las señales de salida la llevan a los procesos enlazados (enlaces) y los mensajes 'DOWN' a los que lo monitorizan (monitores); los informes de error la muestran.

Cómo termina el procesoRazón de salidaInforme de error
Su primera llamada retornanormalNinguno
exit(Reason) (también normal, kill)ReasonNinguno
Un error (error/1,2,3, badarith, {badmatch, V}, undef, ...){Reason, Stack}Sí
Un throw(Value) no capturado{{nocatch, Value}, Stack}Sí
Lo termina una señal de salida (señales de salida)La razón de la señal, killed para exit(Pid, kill)Ninguno

Un informe de error se escribe en stderr cuando el proceso termina, después de vaciar la salida estándar, con el formato del manejador de logger por defecto de OTP:

=ERROR REPORT==== 8-Oct-2026::03:42:15.983000 ===
Error in process <0.8.0> with exit value:
{boom,[{crash_reports,'-main/1-fun-6-',0,[]}]}

La cabecera lleva la hora local; la razón se presenta como lo hace ~p. El proceso principal no escribe ninguno: su excepción no capturada es la del programa (ejecutables).

Mensajes

Dest ! Msg y erlang:send(Dest, Msg) evalúan primero Dest y devuelven Msg.

DestEfecto
El pid de un proceso vivoMsg se copia de forma plana en el heap del receptor (copia entre heaps), como OTP copia los mensajes (uno grande, en un bloque que el receptor asume, traspaso de mensajes), y se añade a su buzón de señales; para un receptor que se ejecuta en otro hilo de trabajo, en un búfer entre sus llegadas que toma la próxima vez que las consulta (búferes de llegadas)
El pid de un proceso que ha terminadoNada; el envío tiene éxito
Un nombre registradoComo para su pid; badarg cuando ningún proceso vivo tiene ese nombre
{Name, nonode@nohost} de dos átomosComo para el pid registrado como Name; nada si no hay ninguno
{Name, Node} para cualquier otro nodoNada (no hay otros nodos)
Una referenciaComo para el propietario de un alias activo; nada en otro caso
Cualquier otra cosabadarg

Búferes de llegadas

Un envío a un proceso que se ejecuta en otro hilo de trabajo no toma ningún bloqueo (creación y desmontaje de procesos):

Receive

receive selecciona entre sus cláusulas como case, sobre los mensajes del buzón:

Un enlace conecta dos procesos en ambos sentidos (Signals en cada contexto: los pids enlazados en el orden de enlace y el indicador trap_exit).

Monitores

Un monitor es unidireccional: el proceso que monitoriza lo mantiene (por referencia, en Signals) y el proceso monitorizado guarda la referencia y el pid del que monitoriza, para poder enviar el mensaje cuando termine.

Nombres registrados

El ejecutor mantiene una tabla de nombres (átomos) a pids, y cada proceso su propio nombre (Signals::name).

Diccionario del proceso

put/2, get/0,1, get_keys/0,1 y erase/0,1 se comportan como en OTP: put/2 y erase/1 devuelven el valor anterior o undefined, erase/0 devuelve todos los {Key, Value} y vacía el diccionario, y las claves se comparan con igualdad exacta (1 y 1.0 son dos claves).

Temporizadores

start_timer/3,4 y send_after/3,4 (builtins/erlang/timers.cpp, scheduler/timers.cpp) arman un temporizador en la rueda del ejecutor (la misma que usan los tiempos de espera de receive) que envía Msg, o {timeout, TimerRef, Msg}, a un pid o a un nombre registrado cuando se dispara.

Introspección

process_info/1,2 (builtins/erlang/introspection.cpp, scheduler/introspection.cpp) lee otro proceso bajo el bloqueo del ejecutor y copia sus términos (mensajes, diccionario) en el heap del llamante; un proceso que se ejecuta en otro hilo de trabajo se lee cuando termina su porción. El pid de un proceso que no está vivo da undefined.

Opciones de spawn

Fuentes: builtins/erlang/spawning.cpp, scheduler/aliases.cpp.

Alias

Un alias es una referencia a la que se pueden enviar mensajes (Alias ! Msg): alias/0,1 (explicit_unalias, o reply para un único mensaje), o un monitor creado con {alias, explicit_unalias | demonitor | reply_demonitor} de monitor/3 (demonitor termina con el monitor, reply_demonitor además termina el monitor con su primer mensaje). unalias/1 termina un alias del llamante. Un envío a una referencia que no es un alias activo, o cuyo propietario ha terminado, se descarta. Un alias de respuesta solo se consume cuando se entrega su mensaje, tras cualquier espera por un propietario ocupado. {tag, Tag} de monitor/3 sustituye 'DOWN' en el mensaje del monitor; los monitores de puertos no aceptan opciones.

Nodos

Un programa Clause es un único nodo no distribuido, nonode@nohost, y responde como un nodo de OTP de ese tipo (builtins/erlang/node.cpp): nodes/0 es [], nodes(this | known) es [nonode@nohost], los demás tipos []; nodes/2 da {nonode@nohost, #{connection_id => undefined, node_type => this}} para las claves solicitadas. is_alive/0 es false, monitor_node/2,3 lanzan error:notalive y disconnect_node/1 devuelve ignored.

Señales de salida

Toda señal de salida procede de un proceso en ejecución (exit/2, exit_signal/2, link/1) o del final de un proceso. El ejecutor actúa sobre ella de inmediato cuando su destino no se ejecuta en otro hilo de trabajo, y si no, en cuanto termina la porción del destino (hilos de trabajo, scheduler/signals): un destino terminado sale de la cola de ejecución o de su espera y se finaliza (señales a sus enlaces, su informe de error escrito, su contexto liberado) antes de que retorne el builtin emisor. Una cadena larga de enlaces termina proceso a proceso sin recursión.

Señal en un procesoSin atrapar salidasAtrapando salidas
exit(Pid, kill), exit_signal(Pid, kill)Termina con la razón killedTermina con la razón killed
Razón normal (de un enlace, o enviada a otro proceso)NadaMensaje {'EXIT', From, normal}
exit(self(), normal)Termina con la razón normal (peculiaridad de OTP)Mensaje {'EXIT', Self, normal}
exit_signal(self(), normal)NadaMensaje {'EXIT', Self, normal}
Cualquier otra razón, incluido kill de un enlaceTermina con esa razónMensaje {'EXIT', From, Reason}

Puertos

Los puertos se especifican en puertos: un puerto está enlazado con quien lo abre, participa en enlaces, monitores, señales de salida y nombres registrados como un proceso, y se comunica con su proceso conectado mediante mensajes.

Suspensión de procesos

erlang:suspend_process/1,2 y erlang:resume_process/1 (scheduler/suspension.cpp): cada suspensión es una retención del destino en el ejecutor, así que un proceso suspendido solo vuelve a ejecutarse cuando se reanudan todas las suspensiones de todos los suspensores; los mensajes y las señales siguen llegando (una señal de salida sigue terminándolo), y process_info(Pid, status) informa de suspended. El final de un suspensor reanuda sus suspensiones. Una suspensión síncrona de un proceso que se ejecuta en otro hilo de trabajo espera a que termine su porción de tiempo; asynchronous retorna de inmediato, {asynchronous, Tag} también envía al llamante {Tag, suspended}, y unless_suspending responde false cuando el llamante ya suspende el proceso. Suspender o reanudar al propio llamante, un proceso terminado, un valor que no sea un pid o unas opciones incorrectas son badarg, al igual que reanudar un proceso que el llamante no suspende.

Builtins

BuiltinComportamiento
spawn(Fun)badarg salvo que Fun sea un fun; si lo es, un proceso nuevo llama a Fun(), lanzando {badarity, {Fun, []}} en ese proceso si la aridad es otra
spawn(M, F, Args)badarg salvo que M y F sean átomos y Args una lista propia; si no, un proceso nuevo llama a M:F(Args...), lanzando undef en ese proceso cuando ningún módulo la exporta y ningún builtin tiene ese nombre
spawn_link(Fun), spawn_link(M, F, Args)Como spawn, y el proceso nuevo queda enlazado con el llamante (enlaces)
is_process_alive(Pid)badarg salvo que Pid sea un pid; true mientras su proceso no haya terminado
spawn_monitor(Fun), spawn_monitor(M, F, Args)Como spawn, devolviendo {Pid, Ref} de un nuevo monitor
link(Pid), unlink(Pid)badarg salvo que Pid sea un pid (enlaces)
monitor(process, Item)badarg para otro tipo u otro elemento; una referencia (monitores); Item es un pid o un nombre registrado
register(Name, Pid), unregister(Name), whereis(Name), registered()Véase nombres registrados; Name debe ser un átomo
demonitor(Ref), demonitor(Ref, Options)badarg salvo que Ref sea una referencia y Options una lista propia de flush e info
exit(Dest, Reason), exit_signal(Dest, Reason)badarg salvo que Dest sea un pid o una referencia; true tras la señal de salida
process_flag(trap_exit, Bool), process_flag(min_heap_size, N), process_flag(save_calls, N)El valor anterior; badarg para otro indicador, un valor no booleano o un tamaño negativo o no entero
erlang:send(Dest, Msg), Dest ! MsgMsg, después de enviarlo (mensajes); send/2 no se importa automáticamente
spawn(Node, ...), spawn_link(Node, ...), spawn_monitor(Node, ...) (/2, /4)Este nodo (nonode@nohost): como sin Node. Otro nodo: el pid inútil de OTP de un nodo que no está activo, un proceso que termina de inmediato con la razón noconnection, así que un enlace o monitor informa de noconnection; badarg para un nodo que no sea un átomo
erlang:send(Dest, Msg, Options)ok, o noconnect para un mensaje a otro nodo con la opción noconnect; opciones nosuspend, noconnect, priority (un mensaje ordinario)
send_nosuspend(Dest, Msg), send_nosuspend(Dest, Msg, [noconnect])true; false para otro nodo con noconnect
link(Pid, Options), exit(Dest, Reason, Options), exit_signal(Dest, Reason, Options)Como sin opciones; Options es [] o [priority] (una señal ordinaria)
process_flag(Pid, save_calls, N)El valor anterior de otro proceso (0..10000); se conserva, pero Clause no guarda llamadas; otros indicadores dan badarg
processes_iterator(), processes_next(Iter)Recorren los procesos vivos: {Pid, Iter1} o none; un proceso lanzado durante el recorrido puede aparecer
bump_reductions(N)true para un entero no negativo; Clause no cuenta reducciones
erlang:suspend_process(Pid), erlang:suspend_process(Pid, Options), erlang:resume_process(Pid)Véase suspensión de procesos
erlang:process_display(Pid, backtrace)true tras escribir la pila de llamadas del proceso vivo Pid en la salida de error estándar, un Module:Function/Arity por línea, la función actual primero; badarg para otro tipo o un proceso terminado

El proceso nuevo se añade al final de la cola del hilo de trabajo de su padre (hilos de trabajo); spawn devuelve su pid de inmediato.