C# Async ops

El nucleo de la programacion asincrona son los objetos Task y Task<T>. Son compatibles con las palabras clave async y await.

Primero hay que reconocer si el codigo se usa para trabajos enlazados a I/O o si son CPU intensivos.

  • Si el codigo “espera” algo como una BBDD o una response de un servidor, es codigo I/O. En este caso hay que usar async y await pero SIN usar Task.Run
  • Si el codigo realiza un calculo costoso, es CPU intensivo. Use async y await y genere otro subproceso con Task.run

Async / Await (Operaciones I/O)

La palabra clave importante aqui es await. Lo que hace es suspender la ejecucion del metodo actual y devolver el control hasta que está lista para seguir.

public Task Main()
{
	string contenido = await LeerPaginaWebAsync("http://example.com");
}

public async Task<string> LeerPaginaWebAsync(string url)
{
	using (HttpClient client = new HttpClient())
	{
		return await client.GetStringAsync(url);
	}
}
Task.Run (Codigo CPU intensivo)

usando Task.Run() fuerzas el invocar un hilo que no sea el hilo pincipal para no bloquearlo. Se usa para procesos intensivos de CPU y bloqueantes.

public Task Main()
{
	// TODO: revisar que el codigo compile y funcione. pseudocodigo
	string contenido = await Task.Run(() => LeerPaginaWebAsync("http://example.com"));
}

public async Task<string> LeerPaginaWebAsync(string url)
{
	using (HttpClient client = new HttpClient())
	{
		return await client.GetStringAsync(url);
	}
	// hacer aqui una operacion extra muy CPU intensiva
}
Task.WhenAll (Esperando a que se completen varias tareas concurrentes)

Para situaciones en las que se necesiten recuperar fragmentos de datos al mismo tiempo.

public Task Main()
{
	// TODO: revisar que el codigo compile y funcione. pseudocodigo
	var urls = new List<string>
	{
		"http://example.com", 
		"http://example.org", 
		"http://example.net", 
		"http://example.info", 
		"http://example.edu", 
		"http://example.co", 
		"http://example.io", 
		"http://example.ai", 
		"http://example.biz", 
		"http://example.online"
	}

	// se inicia la lectura  de todas las paginas web de manera concurrente
	var tasksDeLectura(urls.Select(url => LeerPaginaWebAsync(url)).ToList());

	// esperar a que todas las tareas de lectura se completen
	string[] contenidos = await Task.WhenAll(tasksDeLectura);

	foreach (var contenido in contenidos) 
	{
		// hacer algo con las paginas web
	}

}

public async Task<string> LeerPaginaWebAsync(string url)
{
	using (var client = new HttpClient())
	{
		return await client.GetStringAsync(url);
	}
}