前言
Task是从 .NET Framework 4 开始引入的一项基于队列的异步任务(TAP)模式,从 .NET Framework 4.5 开始,任何使用 async/await 进行修饰的方法,都会被认为是一个异步方法;实际上,这些异步方法都是基于队列的线程任务,从你开始使用 Task 去运行一段代码的时候,实际上就相当于开启了一个线程,默认情况下,这个线程数由线程池 ThreadPool 进行管理的。
1. Task 的使用方法
1.1 最简单的使用方式
static void EasyTask()
{
// 执行一个无返回值的任务
Task.Run(() =>
{
Console.WriteLine("runing...");
});
// 执行一个返回 int 类型结果的任务
Task.Run<int>(() =>
{
return new Random().Next();
});
// 声明一个任务,仅声明,不执行
Task t = new Task(() =>
{
Console.WriteLine("");
});
}
2.1 使用 TaskFactory 工厂开始异步任务
static void Factory()
{
List<Task<int>> tasks = new List<Task<int>>();
TaskFactory factory = new TaskFactory();
tasks.Add(factory.StartNew<int>(() =>
{
return 1;
}));
tasks.Add(factory.StartNew<int>(() =>
{
return 2;
}));
foreach (var t in tasks)
{
Console.WriteLine("Task:{0}", t.Result);
}
}
2.3 执行上面的代码,输出结果如下
3. 处理 Task 中的异常
3.1 模拟抛出异常
static void SimpleTask()
{
var task = Task.Run(() =>
{
Console.WriteLine("SimpleTask");
Task.Delay(1000).Wait();
throw new Exception("SimpleTask Error");
});
try
{
task.Wait();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
if (task.IsCompletedSuccessfully)
{
Console.WriteLine("IsCompleted");
}
}
3.2 执行程序,输出结果
4. 同步上下文
4.1 获取当前线程上下文对象
static void TaskSynchronizationContext()
{
var UISyncContext = TaskScheduler.FromCurrentSynchronizationContext();
var t1 = Task.Factory.StartNew<int>(() =>
{
return 1;
});
t1.ContinueWith((atnt) =>
{
// 从这里访问 UI 线程的资源
Console.WriteLine("从这里访问 UI 线程的资源");
}, UISyncContext);
}
5. Task 的运行方式
5.1 基于 ThreadPool 线程池的方式
static void SetThreadPool()
{
var available = ThreadPool.SetMaxThreads(8, 16);
Console.WriteLine("Result:{0}", available);
}
5.2 长时间运行于后台的任务
static void LongTask()
{
Task.Factory.StartNew(() =>
{
Console.WriteLine("LongRunning Task");
}, TaskCreationOptions.LongRunning);
}
6. 有条件的 Task
6.1 使用演示
static void WithTask()
{
var order1 = Task.Run(() =>
{
Console.WriteLine("Order 1");
});
// 匿名委托将等待 order1 执行完成后执行,并将 order1 对象作为参数传入
order1.ContinueWith((task) =>
{
Console.WriteLine("Order 1 Is Completed");
});
var t1 = Task.Run(() => { Task.Delay(1500).Wait(); Console.WriteLine("t1"); });
var t2 = Task.Run(() => { Task.Delay(2000).Wait(); Console.WriteLine("t2"); });
var t3 = Task.Run(() => { Task.Delay(3000).Wait(); Console.WriteLine("t3"); });
Task.WaitAll(t1, t2, t3);
// t1,t2,t3 完成后输出下面的消息
Console.WriteLine("t1,t2,t3 Is Complete");
var t4 = Task.Run(() => { Task.Delay(1500).Wait(); Console.WriteLine("t4"); });
var t5 = Task.Run(() => { Task.Delay(2000).Wait(); Console.WriteLine("t5"); });
var t6 = Task.Run(() => { Task.Delay(3000).Wait(); Console.WriteLine("t6"); });
Task.WaitAny(t4, t5, t6);
// 当任意任务完成时,输出下面的消息,目前按延迟时间计算,在 t4 完成后立即输出下面的信息
Console.WriteLine("t4,t5,t6 Is Complete");
var t7 = Task.Run(() => { Task.Delay(1500).Wait(); Console.WriteLine("t7"); });
var t8 = Task.Run(() => { Task.Delay(2000).Wait(); Console.WriteLine("t8"); });
var t9 = Task.Run(() => { Task.Delay(3000).Wait(); Console.WriteLine("t9"); });
var whenAll = Task.WhenAll(t7, t8, t9);
// WhenAll 不会等待,所以这里必须显示指定等待
whenAll.Wait();
// 当所有任务完成时,输出下面的消息
Console.WriteLine("t7,t8,t9 Is Complete");
var t10 = Task.Run(() => { Task.Delay(1500).Wait(); Console.WriteLine("t10"); });
var t11 = Task.Run(() => { Task.Delay(2000).Wait(); Console.WriteLine("t11"); });
var t12 = Task.Run(() => { Task.Delay(3000).Wait(); Console.WriteLine("t12"); });
var whenAny = Task.WhenAll(t10, t11, t12);
// whenAny 不会等待,所以这里必须显示指定等待
whenAny.Wait();
// 当任意任务完成时,输出下面的消息,目前按延迟时间计算,在 t10 完成后立即输出下面的信息
Console.WriteLine("t10,t11,t12 Is Complete");
}
6.2 执行上面的代码,输出结果如下
结束语
- 本章简要介绍了基于队列的异步任务(TAP)使用方式
- 介绍了TAP 运行的方式、以及异常处理
- 同时还介绍了如何使用 UI 线程同步上下文对象,以及有条件使用 TAP 的各种方法