asíncrono vs sin bloqueo

373

¿Cuál es la diferencia entre llamadas asíncronas y no bloqueantes? ¿También entre bloqueo y llamadas sincrónicas (con ejemplos, por favor)?

usuario331561
fuente
44
Relacionado: stackoverflow.com/a/9489547/194894
Flujo
1
Entendí bien las diferencias al leer el libro <Programación de redes Unix> Col ​​1, Capítulo 6.
Bin
2
Un artículo interesante: Aumente el rendimiento de la aplicación utilizando E / S asíncrona . Clasifica los paradigmas de E / S en 4 categorías: (1) Bloqueo + Sincrónico, (2) Sin bloqueo + Sincrónico, (3) Bloqueo + Asincrónico y (4) Sin bloqueo + Asincrónico.
MS Dousti
@MSDousti Un experto de Google me dijo que esto está mal de alguna manera.
Rick
@MSDousti Después de un estudio, creo que no hay combinación (3) y (2) como usted describe en los comentarios. Verifique la definición de Asíncrono, se trata de lo mismo de Sin bloqueo. Como puede ver, la respuesta principal confirma mi opinión. La función de sondeo y devolución de llamada son simplemente formas / patrones para implementar Asíncrono. Sí, estoy diciendo que Bloqueo, Sincrónico y Sin bloqueo, Asíncrono son 2 pares de sinónimos.
Rick

Respuestas:

305

En muchas circunstancias, son nombres diferentes para la misma cosa, pero en algunos contextos son bastante diferentes. Entonces eso depende. La terminología no se aplica de manera totalmente coherente en toda la industria del software.

Por ejemplo, en la clásica API de sockets, un socket sin bloqueo es uno que simplemente regresa inmediatamente con un mensaje de error especial "bloquearía", mientras que un socket de bloqueo se habría bloqueado. Tiene que usar una función separada como selecto pollpara averiguar cuándo es un buen momento para volver a intentarlo.

Pero los zócalos asíncronos (como lo admiten los zócalos de Windows), o el patrón de E / S asíncrono utilizado en .NET, son más convenientes. Llama a un método para iniciar una operación, y el marco le devuelve la llamada cuando termina. Incluso aquí, hay diferencias básicas. Los sockets asíncronos Win32 "reúnen" sus resultados en un subproceso de GUI específico al pasar mensajes de Windows, mientras que .NET asincrónico IO es de subproceso libre (no sabe en qué subproceso se llamará a su devolución de llamada).

Entonces no siempre significan lo mismo. Para destilar el ejemplo del zócalo, podríamos decir:

  • Bloquear y sincrónico significan lo mismo: llamas a la API, cuelga el hilo hasta que tenga algún tipo de respuesta y te lo devuelve.
  • Sin bloqueo significa que si una respuesta no se puede devolver rápidamente, la API regresa inmediatamente con un error y no hace nada más. Por lo tanto, debe haber alguna forma relacionada de consultar si la API está lista para ser llamada (es decir, para simular una espera de manera eficiente, para evitar el sondeo manual en un ciclo cerrado).
  • Asíncrono significa que la API siempre regresa de inmediato, después de haber comenzado un esfuerzo "en segundo plano" para cumplir con su solicitud, por lo que debe haber alguna forma relacionada para obtener el resultado.
Daniel Earwicker
fuente
estado listo IO en lugar de estado completado IO; en Linux ver libaio
Será el
44
Gracias por señalar que los términos son sensibles al contexto y, a veces, pueden usarse de manera inconsistente. Encuentro especialmente en tecnología, pero también en otras áreas, que a menudo es más útil reconocer ese hecho que entrar en debates sobre qué definición precisa es la correcta, como a veces sucede.
Chad NB
2
Seguimiento P: La respuesta parece hacer dos distinciones diferentes entre los términos. Primero, la notificación: el no bloqueo implica que la aplicación debe verificar nuevamente más tarde (sondeo), mientras que el asincrónico implica que podemos olvidarlo y confiar en el marco / SO para que nos notifique por devolución de llamada o publique un evento. En segundo lugar, la acción: no bloquear no hace absolutamente nada más que devolver un error, mientras que asíncrono pone en cola la acción o lo hace "en segundo plano" en algún sentido. ¿Qué diferencia es más importante para distinguir los términos? ¿Alguna distinción está más fuertemente asociada con un término? ¿O es ambiguo?
Chad NB
2
@ChadNB: como términos, el no bloqueo está fuertemente asociado con el sondeo. Con respecto a la pregunta de si la API "recuerda" su intento de llamarlo: la única razón para que la API recuerde es para devolverle la llamada. Si va a llamarlo para volver a sondear, entonces ya debe mantener el estado necesario para saber hacer esa llamada posterior, por lo que la API no agregaría valor al mantener el estado.
Daniel Earwicker
66
En lugar de decir que la llamada sin bloqueo devuelve un "error", creo que sería más exacto decir que una llamada sin bloqueo hace todo lo que se puede hacer esencialmente de inmediato, y luego indica cuánto lo hizo. Para algunas operaciones, la cantidad de trabajo realizado será "todo" o "nada", pero algunas otras operaciones (como E / S de flujo) pueden devolver una indicación cuantitativa. El no bloqueo es semánticamente equivalente al bloqueo con un tiempo de espera muy corto si la implementación de E / S de bloqueo permitirá una operación que se agota sin problemas más tarde (algunos lo hacen, otros no).
supercat
56

síncrono / asíncrono es describir la relación entre dos módulos.
bloquear / no bloquear es describir la situación de un módulo.

Un ejemplo:
Módulo X: "I".
Módulo Y: "librería".
X pregunta a Y: ¿tienes un libro llamado "c ++ primer"?

1) bloqueo: antes de que Y responda X, X sigue esperando allí la respuesta. Ahora X (un módulo) está bloqueando. X e Y son dos hilos o dos procesos o un hilo o un proceso? No lo sabemos

2) sin bloqueo: antes de que Y responda X, X simplemente se va de allí y hace otras cosas. ¿X puede regresar cada dos minutos para verificar si Y ha terminado su trabajo? ¿O X no volverá hasta que Y lo llame? No lo sabemos Solo sabemos que X puede hacer otras cosas antes de que Y termine su trabajo. Aquí X (un módulo) no es bloqueante. X e Y son dos hilos o dos procesos o un proceso? No lo sabemos PERO estamos seguros de que X e Y no podrían ser un hilo.

3) síncrono: antes de que Y responda a X, X sigue esperando allí la respuesta. Significa que X no puede continuar hasta que Y termine su trabajo. Ahora decimos: X e Y (dos módulos) son sincrónicos. X e Y son dos hilos o dos procesos o un hilo o un proceso? No lo sabemos

4) asíncrono: antes de que Y responda X, X se va de allí y X puede hacer otros trabajos. X no volverá hasta que Y lo llame. Ahora decimos: X e Y (dos módulos) son asíncronos. X e Y son dos hilos o dos procesos o un proceso? No lo sabemos PERO estamos seguros de que X e Y no podrían ser un hilo.


Por favor, preste atención a las dos oraciones en negrita anteriores. ¿Por qué la oración en negrita en el 2) contiene dos casos mientras que la oración en negrita en el 4) contiene solo un caso? Esta es una clave de la diferencia entre no bloqueo y asíncrono.

Aquí hay un ejemplo típico sobre sin bloqueo y sincrónico:

// thread X
while (true)
{
    msg = recv(Y, NON_BLOCKING_FLAG);
    if (msg is not empty)
    {
        break;
    }
    sleep(2000); // 2 sec
}

// thread Y
// prepare the book for X
send(X, book);

Puede ver que este diseño no bloquea (puede decir que la mayoría de las veces este bucle hace algo sin sentido, pero a los ojos de la CPU, X se está ejecutando, lo que significa que X no bloquea) mientras que X e Y están sincronizados porque X puede No continúe haciendo ninguna otra cosa (X no puede salirse del bucle) hasta que obtenga el libro de Y.
Normalmente, en este caso, hacer que el bloqueo X sea mucho mejor porque el no bloqueo gasta muchos recursos para un bucle estúpido. Pero este ejemplo es bueno para ayudarlo a comprender el hecho: no bloquear no significa asincrónico.

Las cuatro palabras nos confunden fácilmente, lo que debemos recordar es que las cuatro palabras sirven para el diseño de la arquitectura. Aprender a diseñar una buena arquitectura es la única forma de distinguirlos.

Por ejemplo, podemos diseñar este tipo de arquitectura:

// Module X = Module X1 + Module X2
// Module X1
while (true)
{
    msg = recv(many_other_modules, NON_BLOCKING_FLAG);
    if (msg is not null)
    {
        if (msg == "done")
        {
            break;
        }
        // create a thread to process msg
    }
    sleep(2000); // 2 sec
}
// Module X2
broadcast("I got the book from Y");


// Module Y
// prepare the book for X
send(X, book);

En el ejemplo aquí, podemos decir que

  • X1 no bloquea
  • X1 y X2 son sincrónicos
  • X e Y son asíncronos

Si lo necesita, también puede describir los hilos creados en X1 con las cuatro palabras.

Las cosas más importantes son: ¿cuándo usamos síncrono en lugar de asíncrono? ¿Cuándo usamos bloqueo en lugar de no bloqueo?

¿Por qué Nginx no bloquea? ¿Por qué está bloqueando Apache?

Para hacer una buena elección, debe analizar su necesidad y probar el rendimiento de diferentes arquitecturas. No existe una arquitectura que sea adecuada para diversas necesidades.

Yves
fuente
77
OMI, la mejor respuesta ya que capta la esencia del concepto: la relación entre uno o dos participantes.
Fábio
tanto en 1 como en 3, Y está actuando como un recurso LIMITADO. No hay más Y para ayudar a X
UVM
46
  • Asíncrono se refiere a algo hecho en paralelo , digamos que es otro hilo.
  • El no bloqueo a menudo se refiere al sondeo , es decir, verificar si la condición dada se mantiene (el socket es legible, el dispositivo tiene más datos, etc.)
Nikolai Fetissov
fuente
17
cuando I / O está involucrado, asíncrono generalmente no está "en paralelo", ni "otro hilo", principalmente basado en notificaciones. es decir: no bloquee, no sondee, solo obtenga la señal. por supuesto, se puede argumentar que la señal proviene del "mundo real", que puede considerarse como "otro hilo" ...
Javier
Bueno, sí, podemos discutir la redacción exacta todo el día :)
Nikolai Fetissov
pero ¿cómo explicas el AIO en Linux? que usaba tanto Async como sin bloqueo. AIO LINKS
Djvu
16
Para cualquiera que lea esta respuesta: esto no es discutir sobre una redacción exacta. Del mismo modo que concurrencia y paralelismo no son las mismas nociones y distinguirlas no es un problema de redacción. La asincronía y el paralelismo son dos bestias diferentes y esta respuesta inexacta hace que sean lo mismo.
Ptival
2
Async no necesariamente significa que se realiza en paralelo, vea esta gran publicación en stackoverflow sobre programación concurrente y paralela.
BARJ
17

Poniendo esta pregunta en el contexto de NIO y NIO.2 en java 7, async IO es un paso más avanzado que el no bloqueo. Con las llamadas sin bloqueo de Java NIO, uno establecería todos los canales (SocketChannel, ServerSocketChannel, FileChannel, etc.) como tales llamando AbstractSelectableChannel.configureBlocking(false). Sin embargo, después de que esas llamadas IO regresen, es probable que aún necesite controlar las comprobaciones, como si leer y escribir nuevamente, etc.,
por ejemplo,

while (!isDataEnough()) {
    socketchannel.read(inputBuffer);
    // do something else and then read again
}

Con la API asincrónica en Java 7, estos controles se pueden realizar de formas más versátiles. Una de las 2 formas es usar CompletionHandler. Tenga en cuenta que ambas readllamadas no son de bloqueo.

asyncsocket.read(inputBuffer, 60, TimeUnit.SECONDS /* 60 secs for timeout */, 
    new CompletionHandler<Integer, Object>() {
        public void completed(Integer result, Object attachment) {...}  
        public void failed(Throwable e, Object attachment) {...}
    }
}
Antonio
fuente
3
FileChannelno se puede seleccionar y no se puede configurar para que no se bloquee.
michaelliu
15

Como probablemente pueda ver en la multitud de respuestas diferentes (y a menudo mutuamente excluyentes), depende de a quién le pregunte. En algunos ámbitos, los términos son sinónimos. O podrían referirse a dos conceptos similares:

  • Una interpretación es que la llamada hará algo en el fondo esencialmente sin supervisión para permitir que el programa no se retenga por un largo proceso que no necesita controlar. La reproducción de audio podría ser un ejemplo: un programa podría llamar a una función para reproducir (por ejemplo) un mp3 y, a partir de ese momento, podría continuar con otras cosas y dejar que el sistema operativo gestione el proceso de reproducción del audio en el hardware de sonido .
  • La interpretación alternativa es que la llamada hará algo que el programa necesitará monitorear, pero permitirá que la mayor parte del proceso ocurra en segundo plano y solo notifique al programa en los puntos críticos del proceso. Por ejemplo, el archivo asincrónico IO podría ser un ejemplo: el programa proporciona un búfer al sistema operativo para escribir en el archivo, y el sistema operativo solo notifica al programa cuando la operación se completa o se produce un error.

En cualquier caso, la intención es permitir que el programa no se bloquee a la espera de que se complete un proceso lento; la forma en que se espera que responda el programa es la única diferencia real. El término se refiere al que también cambia de programador a programador, de lenguaje a lenguaje o de plataforma a plataforma. O los términos pueden referirse a conceptos completamente diferentes (como el uso de síncrono / asíncrono en relación con la programación de subprocesos).

Lo siento, pero no creo que haya una sola respuesta correcta que sea globalmente cierta.

Mac
fuente
1
+1 Buena respuesta. Las personas deben ser conscientes de que "asincrónico" puede significar un enfoque sin bloqueo o con el enfoque asincrónico de Microsoft (basado en eventos / devolución de llamada).
Ingeniero
14

Una llamada sin bloqueo regresa inmediatamente con los datos disponibles: el número total de bytes solicitados, menos o ninguno.

Una llamada asincrónica solicita una transferencia que se realizará en su totalidad (en su totalidad) pero que se completará en algún momento futuro.

Koray Tugay
fuente
sin bloqueo no devuelve ningún resultado nada en absoluto
CEO en Apartico
9

Sin bloqueo: esta función no esperará mientras esté en la pila.

Asíncrono: el trabajo puede continuar en nombre de la llamada de función después de que esa llamada haya abandonado la pila

Frank Schwieterman
fuente
1
@Marenz significa que no puede hacer io sin bloqueo directamente con llamadas posix. Eso no cambia el significado que da aquí.
tmc
@Marenz Lo que solo significa que la bandera se ignora para los archivos. No afecta el significado de esta respuesta.
Marqués de Lorne
8

Sincrónico se define como sucediendo al mismo tiempo.

Asíncrono se define como no sucediendo al mismo tiempo.

Esto es lo que causa la primera confusión. Sincrónico es en realidad lo que se conoce como paralelo. Mientras asíncrono es secuencial, haga esto, luego haga eso.

Ahora todo el problema se trata de modelar un comportamiento asincrónico, porque tienes alguna operación que necesita la respuesta de otra antes de que pueda comenzar. Por lo tanto, es un problema de coordinación, ¿cómo sabrá que ahora puede comenzar esa operación?

La solución más simple se conoce como bloqueo.

El bloqueo es cuando simplemente elige esperar a que se haga lo otro y devolverle una respuesta antes de pasar a la operación que lo necesitaba.

Entonces, si necesita poner mantequilla en una tostada y, por lo tanto, primero debe tostarla. La forma en que los coordinarías es que primero tostarías la raza, luego mirarías sin parar la tostadora hasta que esta brille, y luego procederías a ponerles mantequilla.

Es la solución más simple y funciona muy bien. No hay una razón real para no usarlo, a menos que tenga otras cosas que deba hacer que no requieran coordinación con las operaciones. Por ejemplo, lavando algunos platos. ¿Por qué esperar sin hacer nada mirando la tostadora constantemente para que la tostada explote, cuando sabes que tomará un poco de tiempo y podrías lavar un plato entero mientras termina?

Ahí es donde entran en juego otras dos soluciones conocidas respectivamente como no bloqueantes y asincrónicas.

Sin bloqueo es cuando elige hacer otras cosas no relacionadas mientras espera que se realice la operación. Verificando la disponibilidad de la respuesta como mejor le parezca.

Entonces, en lugar de mirar la tostadora para que explote. Ve y lava un plato entero. Y luego miras la tostadora para ver si las tostadas han aparecido. Si no lo han hecho, ve a lavar otro plato, revisando la tostadora entre cada plato. Cuando ves que las tostadas se han reventado, dejas de lavar los platos y, en cambio, tomas las tostadas y pasas a ponerles mantequilla.

Sin embargo, tener que revisar constantemente las tostadas puede ser molesto, imagina que la tostadora está en otra habitación. Entre platos, pierdes el tiempo yendo a esa otra habitación para ver las tostadas.

Aquí viene asíncrono.

Asíncrono es cuando elige hacer otras cosas no relacionadas mientras espera que se realice la operación. Sin embargo, en lugar de verificarlo, delega el trabajo de verificar a otra cosa, podría ser la operación en sí misma o un observador, y tiene esa cosa notificando y posiblemente interrumpe cuando la respuesta está disponible para que pueda proceder a la otra operación que lo necesitaba.

Es una terminología extraña. No tiene mucho sentido, ya que todas estas soluciones son formas de crear una coordinación asincrónica de tareas dependientes. Por eso prefiero llamarlo evented.

Entonces, para este, decides actualizar tu tostadora para que suene cuando las tostadas estén listas. Usted está escuchando constantemente, incluso mientras lava los platos. Al escuchar el pitido, hace cola en su memoria que tan pronto como termine de lavar su plato actual, se detendrá e irá a poner la mantequilla en la tostada. O puede optar por interrumpir el lavado del plato actual y lidiar con la tostada de inmediato.

Si tiene problemas para escuchar el pitido, puede pedirle a su compañero que vigile la tostadora por usted y que le avise cuando la tostada esté lista. Su compañero puede elegir cualquiera de las tres estrategias anteriores para coordinar su tarea de observar la tostadora y decirle cuándo están listas.

En una nota final, es bueno entender que si bien el bloqueo y la sincronización (o lo que prefiero llamar igualado) te permiten hacer otras cosas mientras esperas, no tienes que hacerlo. Puede elegir realizar un bucle constante para verificar el estado de una llamada sin bloqueo, sin hacer nada más. Sin embargo, eso a menudo es peor que bloquear (como mirar la tostadora, luego alejarla y luego volver a mirarla hasta que esté lista), por lo que muchas API sin bloqueo le permiten pasar del modo de bloqueo. Para Evented, puede esperar inactivo hasta que se le notifique. La desventaja en ese caso es que agregar la notificación fue complejo y potencialmente costoso para empezar. Tuviste que comprar una nueva tostadora con función de pitido, o convencer a tu pareja para que la vea por ti.

Y una cosa más, debe darse cuenta de las compensaciones que proporcionan los tres. Uno no es obviamente mejor que los demás. Piensa en mi ejemplo. Si su tostadora es tan rápida, no tendrá tiempo de lavar un plato, ni siquiera comenzará a lavarlo, así de rápido es su tostadora. Comenzar con algo más en ese caso es solo una pérdida de tiempo y esfuerzo. El bloqueo servirá. Del mismo modo, si lavar un plato tomará 10 veces más tiempo que el tostado. Tienes que preguntarte qué es más importante para hacer. El brindis podría enfriarse y endurecerse para entonces, no vale la pena, el bloqueo también lo hará. O deberías elegir cosas más rápidas para hacer mientras esperas. Obviamente, hay más, pero mi respuesta ya es bastante larga, mi punto es que debes pensar en todo eso y en las complejidades de implementar cada uno para decidir si vale la pena, y si es así '

Editar:

Aunque esto ya es largo, también quiero que esté completo, así que agregaré dos puntos más.

1) También existe comúnmente un cuarto modelo conocido como multiplexado . Esto es cuando mientras espera una tarea, inicia otra, y mientras espera ambas, comienza una más, y así sucesivamente, hasta que haya comenzado muchas tareas y luego, espere inactivo, pero en todos ellos. Por lo tanto, tan pronto como haya terminado, puede continuar con el manejo de su respuesta y luego volver a esperar a los demás. Se conoce como multiplexado, porque mientras espera, debe verificar cada tarea una después de la otra para ver si están terminadas, ad vitam, hasta que una esté terminada. Es una extensión un poco superior a la normal sin bloqueo.

En nuestro ejemplo, sería como encender la tostadora, luego el lavaplatos, luego el microondas, etc. Y luego esperar en cualquiera de ellos. Donde verificaría la tostadora para ver si está lista, si no, verificaría el lavavajillas, si no, el microondas y todo de nuevo.

2) Aunque creo que es un gran error, sincrónico a menudo se usa para significar una cosa a la vez. Y muchas cosas asíncronas a la vez. Por lo tanto, verá el bloqueo sincrónico y el no bloqueo utilizados para referirse al bloqueo y al no bloqueo. Y el bloqueo asincrónico y el no bloqueo solían referirse a multiplexado e igualado.

Realmente no entiendo cómo llegamos allí. Pero cuando se trata de E / S y Computación, síncrono y asíncrono a menudo se refieren a lo que se conoce mejor como no superpuesto y superpuesto. Es decir, asíncrono significa que IO y Computación se superponen, es decir, que suceden simultáneamente. Si bien sincrónico significa que no lo son, suceden de manera secuencial. Para el bloqueo sincrónico, eso significaría que no inicia otro IO o Computación, solo está ocupado esperando y simulando una llamada de bloqueo. Desearía que la gente dejara de usar mal sincrónicamente y de forma asincrónica. Entonces no lo estoy alentando.

Didier A.
fuente
¿No está seguro de por qué dijo "Sincrónico se define como sucediendo al mismo tiempo"? La idea es que no es concurrente, es decir, que no ocurre al mismo tiempo.
Helsing
¡Fue una gran analogía! ¡Lo acabas de tostar!
d-coder
@Helsing Eso es literalmente lo que significa la palabra. Sincrónico significa la misma hora, y asincrónico significa no la misma hora: p. La razón por la que algo es asíncrono es porque no puede suceder al mismo tiempo, debe suceder antes o después. Si pudiera ocurrir al mismo tiempo, simplemente podría paralelizarlo, o hacerlo en cualquier orden, y no necesitaría una sincronización explícita. Es por eso que la programación asincrónica se trata de hacer esto, luego aquello, esperar estas cosas y luego, etc. Porque ninguna de esas cosas puede suceder juntas al mismo tiempo.
Didier A.
@Helsing Además, concurrente no es lo mismo que paralelo. No significa que sucedan dos cosas al mismo tiempo, solo significa que se avanza en más de una cosa antes de que cualquiera de ellas termine. Eso podría lograrse con la paralelización, o simplemente con el entrelazado, también conocido como cambio de tareas.
Didier A.
5

Bloqueo de llamadas: el control regresa solo cuando se completa la llamada.

Llamada sin bloqueo : el control regresa de inmediato. El sistema operativo posterior de alguna manera notifica al proceso que la llamada se ha completado.


Programa sincrónico : un programa que utiliza llamadas de bloqueo . Para no congelarse durante la llamada, debe tener 2 o más subprocesos (es por eso que se llama Sincrónico: los subprocesos se ejecutan sincrónicamente).

Programa asincrónico : un programa que utiliza llamadas sin bloqueo . Puede tener solo 1 hilo y seguir siendo interactivo.

Babken Vardanyan
fuente
1
Llamada sin bloqueo: el control regresa después de hacer todo lo que se puede hacer esencialmente de inmediato; El método indica cuánto se hizo. Eso es diferente de una llamada asincrónica, que se comporta como usted describió para bloquear la llamada.
Supercat
0

Difieren solo en ortografía. No hay diferencia en lo que se refieren. Para ser técnico, se podría decir que difieren en énfasis. Sin bloqueo se refiere al flujo de control (no se bloquea). Asíncrono se refiere a cuándo se maneja el evento \ datos (no sincrónicamente).

metal de piedra
fuente
0

Los modelos de bloqueo requieren que la aplicación de inicio se bloquee cuando se inicia la E / S. Esto significa que no es posible superponer el procesamiento y las E / S al mismo tiempo. El modelo síncrono sin bloqueo permite la superposición de procesamiento y E / S, pero requiere que la aplicación verifique el estado de la E / S de forma recurrente. Esto deja una E / S asincrónica sin bloqueo, que permite la superposición de procesamiento y E / S, incluida la notificación de la finalización de E / S.

P.Gurung
fuente
-2

Bloqueo: el control vuelve a invocar el preceso después de que se completa el procesamiento de la primitiva (sincronización o asíncrona)

Sin bloqueo: el control vuelve a procesarse inmediatamente después de la invocación

Moslema
fuente
10
Esto ni siquiera responde a lo que se pregunta.
Koray Tugay