remote protocolo protocol dcerpc language-agnostic message-passing method-invocation

language-agnostic - protocolo - remote protocol call



¿Cuál es la diferencia entre el paso de mensajes y la invocación de métodos? (5)

¿Hay alguna diferencia entre el paso de mensajes y la invocación de métodos, o pueden considerarse equivalentes? Esto es probablemente específico para el idioma; muchos idiomas no admiten el paso de mensajes (aunque todos los que puedo pensar en métodos de soporte) y los que sí pueden tener implementaciones completamente diferentes. Además, hay grandes diferencias en la invocación de métodos dependiendo del idioma (C vs. Java vs Lisp versus tu idioma favorito). Creo que esto es agnóstico del lenguaje. ¿Qué puede hacer con un método pasado que no puede hacer con un método invocado y viceversa (en su idioma favorito)?


¿Hay alguna diferencia entre el paso de mensajes y la invocación de métodos, o pueden considerarse equivalentes?

Son similares Algunas diferencias:

Los mensajes se pueden pasar de forma síncrona o asíncrona (por ejemplo, la diferencia entre SendMessage y PostMessage en Windows)

Puede enviar un mensaje sin saber exactamente a qué objeto remoto lo está enviando.

El objeto de destino podría estar en una máquina remota o en O / S.


Al usar Objective-C como un ejemplo de mensajes y Java para los métodos, la principal diferencia es que cuando pasa los mensajes, el Objeto decide cómo quiere manejar ese mensaje (generalmente resulta en un método de instancia en el Objeto al que se llama).

Sin embargo, en Java, la invocación de métodos es una cosa más estática, ya que debe tener una referencia a un Objeto del tipo al que está llamando el método, y un método con el mismo nombre y firma de tipo debe existir en ese tipo, o el compilador se quejará Lo que es interesante es que la llamada real es dinámica, aunque esto no es obvio para el programador.

Por ejemplo, considere una clase como

class MyClass { void doSomething() {} } class AnotherClass { void someMethod() { Object object = new Object(); object.doSomething(); // compiler checks and complains that Object contains no such method. // However, through an explicit cast, you can calm the compiler down, // even though your program will crash at runtime ((MyClass) object).doSomething(); // syntactically valid, yet incorrect } }

Sin embargo, en Objective-C, el compilador simplemente le envía una advertencia por pasar un mensaje a un Objeto que cree que el Objeto puede no entender, pero ignorarlo no impide que su programa se ejecute.

Si bien esto es muy poderoso y flexible, puede resultar en errores difíciles de encontrar cuando se usa incorrectamente debido a la corrupción de la pila.

Adaptado del artículo here . También vea this artículo para más información.


IIRC, se ha demostrado formalmente que son equivalentes. No hace falta pensar demasiado para indicar que deberían serlo. Todo lo que necesita es ignorar, por un momento, la equivalencia directa de la dirección llamada con un punto real en la memoria, y considerarla simplemente como un número. Desde este punto de vista, el número es simplemente un identificador abstracto que identifica de manera única un tipo particular de funcionalidad que desea invocar.

Incluso cuando invoca funciones en la misma máquina, no existe ningún requisito real de que la dirección llamada especifique directamente la dirección física (o incluso virtual) de la función llamada. Por ejemplo, aunque casi nadie los usa realmente, las puertas de tareas en modo protegido de Intel permiten que se realice una llamada directamente a la propia puerta de tareas. En este caso, solo la parte del segmento de la dirección se trata como una dirección real, es decir, cualquier llamada a un segmento de puerta de tarea termina invocando la misma dirección, independientemente del desplazamiento especificado. Si así se desea, el código de procesamiento puede examinar el desplazamiento especificado y utilizarlo para decidir la invocación de un método individual, pero la relación entre el desplazamiento especificado y la dirección de la función invocada puede ser completamente arbitraria.

Una llamada de función de miembro es simplemente un tipo de paso de mensaje que proporciona (o al menos facilita) una optimización en el caso de que el cliente y el servidor del servicio en cuestión compartan un espacio de direcciones común. La correspondencia 1: 1 entre el identificador de servicio abstracto y la dirección en la que reside el proveedor de ese servicio permite una asignación trivial, excepcionalmente rápida, de uno a otro.

Al mismo tiempo, no se equivoque al respecto: el hecho de que algo se parezca a una llamada de función miembro no impide que se ejecute realmente en otra máquina o de forma asíncrona, o (con frecuencia) ambas. El mecanismo típico para lograr esto es la función proxy que traduce el "mensaje virtual" de una llamada de función miembro a un "mensaje real" que puede (por ejemplo) transmitirse a través de una red según sea necesario (por ejemplo, DCOM de Microsoft y CORBA). esto de manera bastante rutinaria).


Realmente no son lo mismo en la práctica. El paso de mensajes es una forma de transferir datos e instrucciones entre dos o más procesos paralelos. La invocación de métodos es una forma de llamar a una subrutina. La concurrencia de Erlang se basa en el concepto anterior con su Programación Orientada Concurrente.

Lo más probable es que el paso de mensajes implique una forma de invocación de métodos, pero la invocación de métodos no implica necesariamente el paso de mensajes. Si lo hiciera sería mensaje de paso. El paso de mensajes es una forma de realizar la sincronización entre procesos paralelos. La invocación del método generalmente significa actividades sincrónicas. La persona que llama espera a que el método termine antes de que pueda continuar. El paso de mensajes es una forma de coroutine. Método de invocación es una forma de subrutina.

Todas las subrutinas son corutinas, pero todas las subrutinas no son subrutinas.


como primera aproximación, la respuesta es: ninguna, siempre que "se comporte normalmente"

Aunque mucha gente cree que existe, técnicamente, suele ser lo mismo: una búsqueda en caché de un fragmento de código que se ejecutará para una determinada operación con nombre (al menos para el caso normal). Llamar al nombre de la operación un "mensaje" o un "método virtual" no hace una diferencia.

PERO: el lenguaje Actor es realmente diferente: al tener objetos activos (cada objeto tiene una cola de mensajes implícita y un subproceso de trabajo, al menos conceptualmente), el procesamiento paralelo se hace más fácil de manejar (google también "comunica procesos secuenciales" para más información).

PERO: en Smalltalk, es posible envolver objetos para que sean como actores, sin cambiar realmente el compilador, la sintaxis o incluso la recompilación.

PERO: en Smalltalk, cuando intenta enviar un mensaje que el receptor no confirma (es decir, "someObject foo: arg"), se crea un objeto de mensaje, que contiene el nombre y los argumentos, y se pasa ese objeto de mensaje. como argumento al mensaje "doesNotUnderstand". Por lo tanto, un objeto puede decidir por sí mismo cómo tratar con los envíos de mensajes no implementados (también llamadas llamadas de un método no implementado). Por supuesto, puede empujarlos a una cola para que un proceso de trabajo los secuencie ...

Por supuesto, esto es imposible con idiomas tipificados estáticamente (a menos que haga un uso intensivo de la reflexión), pero en realidad es una característica MUY útil. Los objetos proxy, la carga de código a pedido, las llamadas a procedimientos remotos, el código de aprendizaje y auto-modificación, los programas de adaptación y auto-optimización, las envolturas de corba y dcom, las colas de trabajadores se basan en ese esquema. Puede ser mal utilizado y provocar errores de tiempo de ejecución, por supuesto. Así que es una espada de dos caras. Afilado y poderoso, pero peligroso en la mano de los principiantes ...

EDITAR: Estoy escribiendo sobre implementaciones de lenguaje aquí (como en Java vs. Smalltalk, no en mecanismos entre procesos.