2009-10-24 22 views
7

Estoy usando métodos asíncronos en algunos de mis proyectos y me gusta, ya que permite que mi aplicación sea mucho más escalable. Sin embargo, me pregunto cómo los métodos asíncronos realmente funcionan en segundo plano. ¿Cómo sabe .NET (o Windows?) Que se ha completado una llamada? Dependiendo de la cantidad de llamadas asincrónicas que hice, puedo ver que se crean nuevos hilos (aunque no siempre ...). ¿Por qué?¿Cómo funcionan los métodos asíncronos en C#?

Además, me gustaría controlar cuánto tiempo tarda una solicitud en completarse. Para probar el concepto, escribí el siguiente código que llama asíncronamente a un servicio web e inmediatamente después se inicia un cronómetro.

for (int i = 0; i < 10000; i++) 
{ 
    myWebService.BeginMyMethod(new MyRequest(), result, new AsyncCallback(callback), i); 
    stopWatches[i].Start(); 
} 
// Call back stop the stopwatch after calling EndMyMethod 

esto no funciona ya que todas las peticiones (10000) tienen la misma hora de inicio y la duración va a subir de forma lineal (llamada 0 = 1 duración, llame al 1 = duración de 2, etc.). ¿Cómo podría controlar la duración real de una llamada con método asíncrono (desde el momento en que la solicitud se ejecuta realmente hasta el final)?


ACTUALIZACIÓN: ¿Tiene bloquear un método asíncrono el flujo? Entiendo que usa el .NET ThreadPool, pero ¿cómo sabe un IAsyncResult que se ha completado una llamada y es hora de llamar al método CallBack?

+0

1. ThreadPool, 2. Consulte los detalles sobre cómo funciona el ThreadPool, pero no creo que lo que desea sea posible de forma genérica. http://msdn.microsoft.com/en-us/library/ms973903.aspx –

Respuesta

3

El código es el ferrocarril y el hilo es el tren. A medida que el tren va en el ferrocarril, ejecuta el código.

BeginMyMethod se ejecuta por el hilo principal. Si mira dentro del BeginMyMethod, simplemente agrega un delegado de MyMethod a la cola de ThreadPool.El actual MyMethod es ejecutado por uno de los trenes del grupo de trenes. La rutina de finalización que se llama cuando se realiza MyMethod se ejecuta con el mismo hilo que ejecutó el MyMethod, no con el hilo principal que ejecuta el resto del código. Mientras un subproceso de grupo de subprocesos está ocupado ejecutando MyMethod, el subproceso principal puede montarse en alguna otra parte del sistema de ferrocarriles (ejecutar algún otro código), o simplemente dormir, esperando hasta que se encienda cierto semáforo.

Por lo tanto no hay tal cosa como IAsyncResult "saber" cuándo llamar a la rutina de finalización, en cambio, rutina de finalización no es más que un delegado llamado por el hilo de la agrupación de hebras justo después de que ha hecho ejecutar MyMethod.

Espero que no te importe la analogía del tren algo infantil, sé que me ayudó más de una vez al explicar el subprocesamiento múltiple a las personas.

+0

¡Me gusta la analogía del tren! ¡Gracias! :) – Martin

1

El quid de la cuestión es que al llamar al Begin se pone en cola una solicitud para ejecutar su método. El método se ejecuta realmente en ThreadPool, que es un conjunto de subprocesos de trabajo proporcionados por el tiempo de ejecución.

El subproceso de subprocesos es un conjunto fijo de subprocesos para crujir mediante tareas asincrónicas a medida que se colocan en la cola. Eso explica por qué ve que el tiempo de ejecución es cada vez más largo: sus métodos pueden ejecutarse cada uno aproximadamente al mismo tiempo, pero no comienzan hasta que se hayan ejecutado todos los métodos anteriores en la cola.

Para controlar el tiempo que lleva ejecutar realmente el método async, debe iniciar y detener el temporizador al principio y al final de su método.

Aquí están los documentos para la clase ThreadPool, y un artículo sobre async methods que explica mejor lo que está sucediendo.

1

Los métodos asíncronos funcionan utilizando .NET ThreadPool. Impulsarán el trabajo en un subproceso ThreadPool (creando uno si es necesario, pero usualmente reutilizando uno) para trabajar en segundo plano.

En su caso, puede hacer lo que está haciendo, sin embargo, tenga en cuenta que el ThreadPool tiene un número limitado de subprocesos con los que funcionará. Vas a engendrar tu trabajo en hilos de fondo, y el primero se ejecutará inmediatamente, pero después de un tiempo, se pondrán en cola, y no funcionarán hasta que las "tareas" se ejecuten por completo. Esto dará la apariencia de que los hilos tardan más y más tiempo.

Sin embargo, los criterios de su cronómetro son un poco defectuosos. Debe medir el tiempo total necesario para completar N tareas, no N veces para completar una tarea. Esta será una medida mucho más útil.

0

Es posible que la mayoría del tiempo de ejecución ocurra antes del BeginMyMethod(). En ese caso, su medida será demasiado baja. De hecho, dependiendo de la API, BeginMyMethod() puede llamar a la devolución de llamada antes de salir de la pila. Cambiando la llamada a StopWatch.Start() debería ayudar a continuación.

Cuestiones relacionadas