正文
使用TPL取回Task中的运行结果的三种方式
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
概念:TPL( Task Parallel Library) 任务并行库
使用Task类执行多线程操作要比直接使用自己手工创建Thread效率高很多。
默认情况下,TPL使用线程池中的线程执行Task,但是工作结束之后,调用者线程怎么取回执行线程的工作结果呢?
这里有三种方法:
1.使用经典的线程同步手段:
可以使用线程同步对象。比如ManualResetEvent
在任务方法中设置ManualResetEvent状态为Signaled
调用者示例代码:
示例代码:
/// <summary>
/// 用于保存处理结果的共享资源
/// </summary>
private static long result = ;
/// <summary>
/// 用于通知启动任务的线程处理工作已完成
/// </summary>
static ManualResetEvent mre = new ManualResetEvent(false);
static void Main(string[] args)
{
Action<object> taskMethod = (end) =>
{
long sum = ;
for (int i = ; i < (int) end; i++)
sum += i;
//保存处理结果(使用Interlocked实现原子操作,无需加锁)
Interlocked.Exchange(ref result, sum);
//通知调用者,工作已经完成,可以取回结果了
mre.Set();
};
//启动异步任务
Task tsk = new Task(taskMethod,);
tsk.Start();
//等待并行处理的完成已取回结果
mre.WaitOne();
Console.WriteLine("程序运行结果为{0}",Program.result);
Console.ReadKey();
}
这种方法混杂了TPL与传统多线程开发方式,不推荐使用
2.使用Task<T>,Result属性
示例代码:
static void Main(string[] args)
{
Func<object, long> del = (end) =>
{
long sum = ;
for (int i = ; i < (int) end; i++)
sum += i;
return sum;
};
Task<long> tsk = new Task<long>(del,);
tsk.Start();
Console.WriteLine("程序运行结果为{0}",tsk.Result);
Console.ReadKey();
}
这种编程方式代码简洁,开发中可用,但是调用者线程必须阻塞等待任务结束。不适合在服务端应用中使用
3.基于回调模式的结果取回
TPL中有一个ContinueWith()方法,可用于创建前赴后继的工作任务
这里调用者线程不是阻塞等待的。适合在服务端应用程序中使用。
示例代码
static void Main(string[] args)
{
Func<object, long> ProcessData = (end) =>
{
long sum = ;
for (int i = ; i < (int)end; i++)
{
sum += i;
throw new DivideByZeroException();
}
return sum;
};
//用于取回处理结果的函数
Action<Task<long>> GetResult = (finishedTask) =>
{
//依据任务状态,决定后继处理工作
if (finishedTask.IsFaulted)
Console.WriteLine("任务在执行时发生异常:{0}", finishedTask.Exception);
else
Console.Write("程序运行结果为{0}", finishedTask.Result);
}; //创建并行处理数据的任务对象
Task<long> tskProcess = new Task<long>(ProcessData, ); //当数据处理结束时,自动启动下一个工作任务,取回上一任务的处理结果
Task tskGetResult = tskProcess.ContinueWith(GetResult); //开始并行处理数据……
tskProcess.Start(); Console.ReadKey();
}