2012-05-02 14 views
32

Estoy tratando de comprender el propósito de TaskCompletionSource y su relación con el trabajo asincrónico/sin hilo. Creo que tengo una idea general, pero quiero asegurarme de que mi comprensión sea correcta.TaskCompletionSource - Intentando comprender el trabajo asincrónico sin hilo

Primero comencé a buscar en la Biblioteca de tareas paralelas (TPL) para descubrir si había una buena manera de crear su propio trabajo sin hilo/asincrónico (digamos que está intentando mejorar la escalabilidad de su sitio ASP.NET) más la comprensión del TPL parece que será muy importante en el futuro (async/await). Lo que me llevó al TaskCompletionSource.

Desde mi punto de vista, parece que agregar TaskCompletionSource a una de sus clases no hace mucho para hacer que su codificación sea asíncrona; si todavía está ejecutando el código de sincronización, la llamada a su código se bloqueará. Creo que esto es cierto incluso para las API de Microsoft. Por ejemplo, digamos en DownloadStringTaskAsync fuera de la clase WebClient, cualquier código de configuración/sincronización que estén haciendo inicialmente se bloqueará. El código que está ejecutando debe ejecutarse en algún subproceso, ya sea el actual o tendrá que derivar uno nuevo.

Así que usa TaskCompletionSource en su propio código cuando llama a otras async llamadas de Microsoft, por lo que el cliente de sus clases no tiene que crear un nuevo hilo para que su clase no se bloquee.

No estoy seguro de cómo Microsoft hace sus API asincrónicas internamente. Por ejemplo, hay un nuevo método async fuera del SqlDataReader para .Net 4.5. Sé que hay puertos de terminación IO. Creo que es una abstracción de nivel inferior (C++?) Que probablemente la mayoría de los desarrolladores de C# no usarán. No estoy seguro de si los puertos de terminación IO funcionarán para las llamadas de red o de base de datos (HTTP) o si solo se utilizan para el archivo IO.

Entonces la pregunta es, ¿estoy en lo correcto en mi entendimiento correcto? ¿Hay ciertas cosas que he representado incorrectamente?

+0

¿cuál es la pregunta aquí? –

+0

Si mi comprensión es correcta ... no estoy seguro si es o no – coding4fun

Respuesta

53

TaskCompletionSource se utiliza para crear objetos Task que no ejecutan código.

Son utilizados bastante por las nuevas API asincrónicas de Microsoft, cada vez que hay operaciones asíncronas basadas en E/S (u otras operaciones asíncronas sin CPU, como un tiempo de espera excedido). Además, cualquier método async Task que escriba utilizará TCS para completar su Task devuelto.

Tengo una publicación de blog Creating Tasks que analiza diferentes formas de crear instancias Task. Está escrito desde una perspectiva async/await (no una perspectiva TPL), pero sigue siendo aplicable aquí.

ver también excelentes mensajes de Stephen Toub:

+0

Gracias Stephen, pero es mi comprensión en el interior correctas? – coding4fun

+1

Cualquier método asíncrono tiene (por supuesto) una porción síncrona que se utiliza para iniciar la operación asincrónica. IIRC, IOCPs se puede utilizar para cualquier tipo de transferencia de datos basada en 'HANDLE', y no es raro (hoy) tener una operación IOCP envuelta en un 'Begin' /' End' envuelto en un método 'async' que lo envuelve en una 'Tarea' (usando' TaskCompletionSource'). –

+0

También estoy tratando de entender el uso de TaskCompletionSource, y estoy un poco confundido acerca de por qué tendría una tarea que no ejecuta el código. Leí tu publicación en el blog; parece que TCS se usa como un evento al que la persona que llama puede suscribirse, pero ¿por qué querría hacerlo cuando puede usar una Tarea normal y esperar hasta que finalice la Tarea? –

4

me gusta la explicación que se proporciona en http://tutorials.csharp-online.net/TaskCompletionSource

(lo siento, el enlace puede estar muerto en el momento)

primeros dos párrafos están por debajo

Hemos visto cómo Task.Run crea una tarea que ejecuta un delegado en un subproceso agrupado (o no agrupado). Otra forma de crear una tarea es con TaskCompletionSource.

TaskCompletionSource le permite crear una tarea de cualquier operación que se inicie y termine un tiempo después. Funciona proporcionándole una tarea "esclava" que conduce de forma manual, indicando cuándo finaliza la operación o fallas. Esto es ideal para el trabajo vinculado a E/S: obtiene todos los beneficios de tareas (con su capacidad para propagar valores de retorno, excepciones, y continuaciones) sin bloquear un hilo durante la operación .

Para utilizar TaskCompletionSource, simplemente crea una instancia de la clase. Es expone una propiedad de tarea que devuelve una tarea en la que puede esperar y adjuntar continuaciones, al igual que con cualquier otra tarea. La tarea, sin embargo, está controlada en su totalidad por el objeto TaskCompletionSource través los métodos siguientes:

public class TaskCompletionSource<TResult> 
{ 
public void SetResult(TResult result); 
public void SetException (Exception exception); 

public void SetCanceled(); 
public bool TrySetResult (TResult result); 
public bool TrySetException (Exception exception); 
public bool TrySetCanceled(); 
... 
} 

llamando a cualquiera de estos métodos señales de la tarea, ponerlo en un completado, en fallo, o cancelado estado (cubriremos el último en la sección "Cancelación"). Se supone que debe llamar a uno de estos métodos exactamente una vez: si se vuelve a llamar, SetResult, SetException o SetCanceled emitirán una excepción, mientras que los métodos Try * devolverán false.

El siguiente ejemplo imprime 42 después de esperar durante cinco segundos:

var tcs = new TaskCompletionSource<int>(); 
new Thread (() =>  { 
         Thread.Sleep (5000); 
         tcs.SetResult (42); 
         })  
      .Start(); 
Task<int> task = tcs.Task; // Our "slave" task. 
Console.WriteLine(task.Result); // 42 

Otras citas interesantes

El poder real de TaskCompletionSource es en la creación de las tareas que no atar los hilos .

.. y más tarde

Nuestro uso de TaskCompletionSource sin un hilo significa que un hilo se dedica únicamente cuando se inicia la continuación, cinco segundos más tarde. Nos podemos demostrar esto comenzando 10.000 de estas operaciones a la vez sin error o recurso excesivo consumo:

+0

El enlace está muerto. –

+1

Buena explicación – Ricky

Cuestiones relacionadas