2010-08-25 15 views
29

¿Hay alguna diferencia entre la transmisión de mensajes y la invocación de métodos, o pueden considerarse equivalentes? Esto es probablemente específico del idioma; muchos lenguajes no soportan 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, existen grandes diferencias en la invocación de métodos según el idioma (C vs. Java vs Lisp frente a tu idioma favorito). Creo que esto es independiente del idioma. ¿Qué se puede hacer con un método pasado que no se puede hacer con un método invocado y viceversa (en su idioma favorito)?¿Cuál es la diferencia entre el paso de mensajes y la invocación de métodos?

+0

¿Quiere decir "¿Qué se puede hacer con un mensaje pasado * que no se puede hacer ..."? Si es así, haré la corrección por ti. – Bevan

Respuesta

3

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

Son similares. Algunas diferencias:

Los mensajes pueden ser transmitidos sincrónica o asincrónica (por ejemplo, la diferencia entre SendMessage y PostMessage en Windows)

Es posible enviar un mensaje sin saber exactamente qué objeto remoto que va a enviar a

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

+0

Disculpas por desenterrar una respuesta hace mucho tiempo, pero con respecto a "el objeto de destino podría estar en una máquina remota o en una O/S": ¿eso es realmente único para el envío de mensajes o la invocación de métodos? Si he entendido correctamente su implicación, está afirmando que es una propiedad de transmisión de mensajes. Si es así, ¿la invocación remota de métodos en Java no es una contradicción a esto? – obfuscation

4

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 al método es una forma de llamar a una subrutina. La concurrencia de Erlang se basa en el concepto anterior con su Programación Concurrente Orientada.

La transmisión de mensajes implica una forma de invocación de método, pero la invocación de método no implica necesariamente la transmisión de mensajes. Si lo hiciera, sería un mensaje que pasa. El paso de mensajes es una forma de realizar la sincronización entre procesos paralelos. Invocación de método generalmente significa actividades sincrónicas. La persona que llama espera que el método termine antes de que pueda continuar. El envío de mensajes es una forma de corutina. Método-invocación es una forma de subrutina.

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

+1

La "transmisión de mensajes" también se puede referir a la forma en que uno llama a los métodos en idiomas como Smalltalk, Objective-C y Ruby. – mipadi

+1

Sí, a estos lenguajes les gusta pensar que es un mensaje que pasa, pero es una subrutina que implica presionar algo en la pila al suspender el método que llama a la subrutina. La implementación es una invocación del método de pila apilada que implica que la persona que llama está bloqueada mientras espera que regrese la rutina de llamada. El mensaje que pasa no tiene esa semántica. No tiene que esperar a que la rutina que invoca terminar sea mi punto. Esa es la diferencia. – chubbsondubs

+0

IMO, el OP realmente no está discutiendo las comunicaciones entre procesos. –

8

como una primera aproximación, la respuesta es: ninguno, siempre y cuando "se comporta normalmente"

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

PERO: el lenguaje Actor es realmente diferente: al tener objetos activos (cada objeto tiene una cola de mensajes implícita y una cadena de trabajo, al menos conceptualmente), becones de procesamiento paralelo más fáciles de manejar (google también "comunicando procesos secuenciales" para más).

PERO: en Smalltalk, es posible envolver objetos para que sean como un actor, sin cambiar realmente el compilador, la sintaxis o incluso recompilar.

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

Por supuesto, esto es imposible con los idiomas estáticos (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 bajo demanda, las llamadas a procedimientos remotos, el código de aprendizaje y auto modificación, los programas de adaptación y autooptimización, los envoltorios corba y dcom, las colas de trabajo se basan en ese esquema. Se puede usar incorrectamente y provocar errores de tiempo de ejecución, por supuesto. Así que es una espada de dos lados. Sharp y poderosa, pero peligroso en manos de principiantes ...

EDIT:. Estoy escribiendo sobre implementaciones de lenguajes aquí (como en Java vs. Smalltalk - mecanismos no entre procesos

7

IIRC, han se ha probado formalmente que es equivalente. No se necesita pensar mucho para al menos indicar que deberían serlo. Sobre todo lo que se necesita es ignorar, por un momento, la equivalencia directa de la dirección llamada con un punto real en la memoria , y considérelo simplemente como un número. Desde este punto de vista, el número es simplemente un identificador abstracto que identifica de forma única un tipo particular de funcionalidad que desea invocar.

Incluso cuando está invocando funciones en la misma máquina, no existe un 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 compuertas de tareas del modo protegido Intel permiten realizar una llamada directamente a la propia compuerta de la tarea. En este caso, solo la parte de 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í lo desea, el código de procesamiento puede examinar el desplazamiento especificado y usarlo para decidir sobre un método individual que se invocará, pero la relación entre el desplazamiento especificado y la dirección de la función invocada puede ser completamente arbitraria.

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

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

5

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

En Java, sin embargo, la invocación de método es algo más estático, porque debe tener una referencia a un Objeto del tipo al que llama el método, y debe existir un método con el mismo nombre y firma de tipo 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 
    } 
} 

En Objective-C sin embargo, el compilador simplemente se emite una advertencia para hacer pasar un mensaje a un objeto que se cree que el objeto no puede entender, pero haciendo caso omiso no detiene la ejecución de su programa.

Si bien esto es muy potente y flexible, puede dar lugar a errores difíciles de encontrar cuando se utiliza incorrectamente debido a la corrupción de la pila.

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

Cuestiones relacionadas