callback erlang otp

callback - Comportamientos Erlang/OTP para principiantes



(5)

¿Qué principiante Erlang / OTP debe saber sobre los comportamientos?

Probablemente lo que está escrito aquí .

¿Es posible describir y entender la noción de comportamiento de OTP en pocas palabras?

Lectura del documento: "Los comportamientos son formalizaciones de estos patrones comunes. La idea es dividir el código de un proceso en una parte genérica (un módulo de comportamiento) y una parte específica (un módulo de devolución de llamada)".

¿Qué significa ''función de devolución de llamada'' en el contexto de Elang / OTP?

Mira el enlace de arriba donde se proporcionan ejemplos de funciones de devolución de llamada.

¿Podemos considerar las devoluciones de llamada en una implementación de comportamiento como métodos anulados en Java?

En términos de Java, un comportamiento probablemente sería una interfaz Java, mientras que una devolución de llamada sería la implementación de uno de los métodos definidos en la interfaz.

El libro dice que la función de devolución de llamada asociada para la función de biblioteca ''gen_server: start_link / 4'' en el siguiente código es ''Module: init / 1''. ¿Eso significa que con init / 1 llamamos gen_server: start_link / 4 función de biblioteca? ¿O eso significa algo más?

Significa que, cada vez que llamas al gen_server: start_link / 4, se llamará a la función Module: init / 1, donde Module es el segundo parámetro que pasaste a la función start_link, con los argumentos que proporcionaste como cuarto argumento. En otras palabras, esto es lo que ocurre detrás de las escenas de start_link / 4:

... start_link(Name, Module, Args, Opts) -> ... Module:init(Args) ... ...

Como entendí del libro "Erlang y OTP en acción", la palabra comportamiento se refiere a:

  • la interfaz de comportamiento, que es un conjunto de funciones;
  • la implementación del comportamiento, que es el código específico de la aplicación (un módulo de devolución de llamada);
  • el contenedor de comportamiento, que es un proceso.

Pregunta:

¿Qué principiante Erlang / OTP debe saber sobre los comportamientos? ¿Es posible describir y entender la noción de comportamiento de OTP en pocas palabras?

¿Qué significa ''función de devolución de llamada'' en el contexto de Elang / OTP?

¿Podemos considerar las devoluciones de llamada en una implementación de comportamiento como métodos anulados en Java?

El libro dice que la función de devolución de llamada asociada para la función de biblioteca ''gen_server: start_link / 4'' en el siguiente código es ''Module: init / 1''.

¿Eso significa que con init / 1 llamamos gen_server: start_link / 4 función de biblioteca? ¿O eso significa algo más?

-module(tr_server). -behaviour(gen_server). -include_lib("eunit/include/eunit.hrl"). %% API -export([ start_link/1, start_link/0, get_count/0, stop/0 ]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -define(SERVER, ?MODULE). -define(DEFAULT_PORT, 1055). -record(state, {port, lsock, request_count = 0}). %%%=================================================================== %%% API %%%=================================================================== %%-------------------------------------------------------------------- %% @doc Starts the server. %% %% @spec start_link(Port::integer()) -> {ok, Pid} %% where %% Pid = pid() %% @end %%-------------------------------------------------------------------- start_link(Port) -> gen_server:start_link({local, ?SERVER}, ?MODULE, [Port], []). %% @spec start_link() -> {ok, Pid} %% @doc Calls `start_link(Port)'' using the default port. s tart_link() -> start_link(?DEFAULT_PORT). %%-------------------------------------------------------------------- %% @doc Fetches the number of requests made to this server. %% @spec get_count() -> {ok, Count} %% where %% Count = integer() %% @end %%-------------------------------------------------------------------- get_count() -> gen_server:call(?SERVER, get_count). %%-------------------------------------------------------------------- %% @doc Stops the server. %% @spec stop() -> ok %% @end %%-------------------------------------------------------------------- stop() -> gen_server:cast(?SERVER, stop). %%%=================================================================== %%% gen_server callbacks %%%=================================================================== init([Port]) -> {ok, LSock} = gen_tcp:listen(Port, [{active, true}]), {ok, #state{port = Port, lsock = LSock}, 0}. handle_call(get_count, _From, State) -> {reply, {ok, State#state.request_count}, State}. handle_cast(stop, State) -> {stop, normal, State}. handle_info({tcp, Socket, RawData}, State) -> do_rpc(Socket, RawData), RequestCount = State#state.request_count, {noreply, State#state{request_count = RequestCount + 1}}; handle_info(timeout, #state{lsock = LSock} = State) -> {ok, _Sock} = gen_tcp:accept(LSock), {noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. %%%=================================================================== %%% Internal functions %%%=================================================================== do_rpc(Socket, RawData) -> try {M, F, A} = split_out_mfa(RawData), Result = apply(M, F, A), gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Result])) catch _Class:Err -> gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Err])) end. split_out_mfa(RawData) -> MFA = re:replace(RawData, "/r/n$", "", [{return, list}]), {match, [M, F, A]} = re:run(MFA, "(.*):(.*)/s*//((.*)/s*//)/s*./s*$", [{capture, [1,2,3], list}, ungreedy]), {list_to_atom(M), list_to_atom(F), args_to_terms(A)}. args_to_terms(RawArgs) -> {ok, Toks, _Line} = erl_scan:string("[" ++ RawArgs ++ "]. ", 1), {ok, Args} = erl_parse:parse_term(Toks), Args. %% test start_test() -> {ok, _} = tr_server:start_link(1055).


P: ¿Qué principiante Erlang / OTP debería saber sobre los comportamientos? ¿Es posible describir y entender la noción de comportamiento de OTP en pocas palabras?

Generalmente, se utiliza un comportamiento en el código para que el compilador pueda generar mensajes de error más intuitivos según su comportamiento, es decir, application / supervisor / gen_server / gen_event / gen_fsm.

Permite al compilador proporcionar mensajes de error específicos para el comportamiento de ex: gen_server

P: ¿Qué significa ''función de devolución de llamada'' en el contexto de Elang / OTP?

Se puede decir que la función de devolución de llamada se toma de la programación de la GUI (al menos similar). Cada vez que ocurre un evento por ej. un clic del mouse allí es una función separada que maneja el clic del mouse.

Por lo tanto siempre que por ej. se llama a una función exportada de un gen_server desde otro módulo, esa función puede tener una función de devolución de llamada (handle_call / handle_cast) con diferentes patrones.

P: ¿Podemos considerar las devoluciones de llamada en una implementación de comportamiento como métodos anulados en Java?

Sí ... tal vez ... no :)

P: El libro dice que la función de devolución de llamada asociada para la función de biblioteca ''gen_server: start_link / 4'' en el siguiente código es ''Module: init / 1''.

gen_server: start_link llama a la función de inicio por sí mismo, como fue respondida por w55 .... (lo siento, un gran nombre).

Espero haber respondido todas sus consultas :)


En lugar de tratar de responder a sus preguntas específicas como lo han hecho otras respuestas, trataré de explicar en términos simples los aspectos básicos de los comportamientos, y le permitiré responder sus propias preguntas sobre la base de comprender esos conceptos básicos.

Un comportamiento es básicamente un marco de manejo de mensajes, donde por "marco" me refiero a la definición clásica de una solución parcial a un problema que puede ser completada y personalizada por el usuario final. Los comportamientos de OTP esencialmente proporcionan:

  • un bucle de mensaje
  • integración con el soporte OTP subyacente para la actualización del código, seguimiento, mensajes del sistema, etc.

Los comportamientos delegan el manejo de mensajes a los módulos de devolución de llamada, o implementaciones de comportamiento como "Erlang y OTP en Acción" los llama. Tras la invocación de su función init/1 , el módulo de devolución de llamada generalmente crea un estado para que el bucle de mensaje lo mantenga en su nombre. El bucle de comportamiento pasa este estado a cada invocación posterior de una función de gestión de mensajes del módulo de devolución de llamada, y cada una de estas invocaciones puede devolver un estado modificado. Las funciones de devolución de llamada también devuelven instrucciones que le indican al ciclo de mensajes de comportamiento qué hacer a continuación.

Aquí hay una versión muy simplificada del ciclo de mensajes en el corazón de un comportamiento:

loop(Callbacks, State) -> {Next, NState} =
 receive M1 ->
 Callbacks:handle_m1(M1,State); M2 -> Callbacks:handle_m2(M2,State); Other -> Callbacks:handle_other(Other,State) end, case Next of
 stop -> ok; _ -> loop(Callbacks, NState) end.

Este ciclo recursivo de cola tiene el módulo Callbacks y la variable State como argumentos. Antes de que se invoque este bucle por primera vez, ya le indicó el comportamiento de su módulo de devolución de llamada, y luego el código base de compatibilidad de comportamiento OTP ya ha llamado a su función de devolución init/1 llamada init/1 para obtener el valor inicial de State .

Nuestro bucle de comportamiento de ejemplo recibe mensajes del formulario M1 , M2 y cualquier otro mensaje, cuyos detalles no importan aquí, y para cada mensaje invoca una función de devolución de llamada diferente en el módulo Callbacks . En este ejemplo, las funciones de devolución de llamada handle_m1 y handle_m2 manejan los mensajes M1 y M2 respectivamente, mientras que el handle_other devolución de llamada maneja todos los otros tipos de mensajes. Tenga en cuenta que State se pasa a cada función de devolución de llamada. Se espera que cada función devuelva una tupla con el primer elemento que le dice al bucle qué hacer a continuación y el segundo elemento que contiene un posible nuevo estado para el bucle - el mismo valor que el State o un nuevo valor diferente - que el bucle almacena en su variable NState . En este ejemplo, si Next es la stop átomo, el ciclo se detiene, pero si es cualquier otra cosa, el ciclo se invoca recursivamente, pasando el nuevo estado NState a la siguiente iteración. Y dado que es recursivo en la cola, el ciclo nunca saltará la pila.

Si gen_server los orígenes de comportamientos OTP estándar como gen_server y gen_fsm , encontrará un bucle muy parecido, pero son mucho más complejos debido a los mensajes del sistema de manejo, los tiempos de espera, el rastreo, las excepciones, etc. Comportamientos estándar también inicie sus bucles en un proceso separado, por lo que también contienen código para iniciar el proceso de bucle y pasarle mensajes.


gen_server: start_link llama a init.


mira el código fuente del módulo gen_server en tu directorio lib de erlang. Está muy bien explicado en el código fuente, los comentarios son muy elaborados.