Creación y Ejecución de Tareas en TPL
En .NET Framework 4.0, Microsoft introdujo la Biblioteca de Paralelismo de Tareas (TPL), un marco centralizado para la programación asincrónica y paralela. Su núcleo es el tipo Task, que representa una operación asíncrona que puede ejecutarse en un hilo independiente o dentro del grupo de hilos (thread pool).
Las tareas pueden combinarse de múltiples formas: ejecutarse en paralelo, esperar su finalización, encadenarse o incluso tener sub-tareas. A partir de C# 5.0, se integraron los keywords async y await, facilitando una sintaxis más limpia para trabajar con tareas.
Ejemplo: Creación de Tareas
A continuación, se muestra cómo crear y lanzar diferentes tipos de tareas usando distintas API de TPL. Algunas se ejecutan en el thread pool, mientras que otrras, marcadas como de larga duración, usan hilos dedicados.
namespace TPLDemo { class Program { static void Main(string[] args) { Console.WriteLine("Ejemplo de Tareas ———— {0}", DateTime.Now);
// Tarea creada manualmente, requiere Start()
var task1 = new Task(() => ExecuteOperation("Tarea 1"));
var task2 = new Task(() => ExecuteOperation("Tarea 2"));
task1.Start();
task2.Start();
// Inicia inmediatamente en el thread pool
Task.Factory.StartNew(() => ExecuteOperation("Tarea 3"));
Task.Run(() => ExecuteOperation("Tarea 4"));
// Tarea de larga duración: usa hilo dedicado
Task.Factory.StartNew(() => ExecuteOperation("Tarea 5"),
TaskCreationOptions.LongRunning);
// Espera breve para observar resultados
Thread.Sleep(1000);
Console.ReadKey();
}
private static void ExecuteOperation(string name)
{
Console.WriteLine(
"Operación en hilo ID: {0}, ¿es del pool? {1}, Nombre: {2}",
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsThreadPoolThread,
name
);
}
}
}
</div>### Obtención de Resultados desde Tareas
Este ejemplo demuestra cómo recuperar valores devueltos por tareas. Se compara el comportamiento entre ejecuciones síncronas y asíncronas.
<div>```
using System;
using System.Threading.Tasks;
namespace TPLDemo
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Operaciones básicas con Tareas ————");
// Ejecución directa (síncrona)
ProcessOperation("Main Thread Task");
// Tarea que se inicia y espera resultado
var task1 = CreateTask("Tarea 1");
task1.Start();
string result1 = task1.Result;
Console.WriteLine("Resultado 1: {0}", result1);
// Tarea ejecutada directamente en el hilo principal
var task2 = CreateTask("Tarea 2");
task2.RunSynchronously();
string result2 = task2.Result;
Console.WriteLine("Resultado 2: {0}", result2);
// Tarea sin bloqueo: verifica estado en bucle
var task3 = CreateTask("Tarea 3");
task3.Start();
while (!task3.IsCompleted)
{
Console.WriteLine("Estado: {0}", task3.Status);
Thread.Sleep(500);
}
Console.WriteLine("Estado final: {0}", task3.Status);
string result3 = task3.Result;
Console.WriteLine("Resultado 3: {0}", result3);
Console.ReadKey();
}
private static string ProcessOperation(string name)
{
Console.WriteLine(
"Hilo ID: {0}, ¿del pool?: {1}, Nombre: {2}",
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsThreadPoolThread,
name
);
Thread.Sleep(2000);
return $"Hilo ID: {Thread.CurrentThread.ManagedThreadId}, Nombre: {name}";
}
static Task<string> CreateTask(string name)
{
return new Task<string>(() => ProcessOperation(name));
}
}
}