.NET多线程

.NET多线程(四)任务

2017-03-12  本文已影响0人  万州大牛

什么是任务?

System.Threading.Tasks.Task

任务代表一个异步操作,是未来的操作

任务非常强大,极大的简化了异步编程,并且能带来显著的性能提升,一旦你发现了她的好处,你会根本停不下来的爱上她

举个简单例子,执行一个操作,我们要查询两张表的数据,我们创建两个任务分别各自查询一张表,是不是快些呢?

任务的线程是后台线程

任务解决的问题是什么?

线程池的缺点

(1)从线程池获取结果并不方便
(2)异常处理不太方便
(3)连续的异步操作不太方便

思想的衍进

(1)线程池是对线程的抽象,让程序员不用关心线程的创建,销毁
(2)任务是对线程池的抽象,让程序员不用关心线程池线程的处理结果,异常,以及连续异步操作

怎么创建任务?

(1)构造函数

【Action 委托,Action<object>】

static void Main(string[] args)
{
    Task task = new Task(() =>
    {
        // True 线程池线程
        Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);
    });
    task.Start();
    Console.ReadLine();
}

(2)Task.Factory.StartNew

static void Main(string[] args)
{
    Task.Factory.StartNew(() =>
    {
        // True 线程池线程
        Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);
    });
    Console.ReadLine();
}

(3)返回结果

【Func<TResult> 委托,Func<object, TResult>】

static void Main(string[] args)
{
    Task<string> task = new Task<string>(() =>
    {
        Thread.Sleep(3 * 1000);
        // True 线程池线程
        return Thread.CurrentThread.IsThreadPoolThread.ToString();
    });
    task.Start();
    task.Wait(); // 等待任务完成
    Console.WriteLine(task.Result); // 打印结果
    Console.ReadLine();
}

(4)不使用线程池

TaskCreationOptions.LongRunning
备注
【当执行耗时操作时,如果使用线程池线程,会导致线程池线程的滥用】

static void Main(string[] args)
{
    Task task = new Task(() =>
    {
        // False 不使用线程池
        Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);
    }, TaskCreationOptions.LongRunning);
    task.Start();
    Console.ReadLine();
}

任务內等待

(1)推荐CancallationToken.WaitHandle.WaitOne()
(2)Thread.Sleep()
(3)不建议
Thread.SpinWait(10000);

等待任务

(1)task.Wait(); 会抛内部异常
(2)Task.WaitAll(task1, task2)
一个异常,全部结束并报告异常
(3)int taskIndex = Task.WaitAny(task1, task2);
任一完成即完成,返回前有异常会报告异常

任务继续

task.ContinueWith

(1)支持1个 task 接多个ContinueWith
(2)ContinueWith返回下一代 task,下一代可以继续ContinueWith

static void Main(string[] args)
{
    Task<string> task = new Task<string>(() =>
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        return "girls,";
    });
    task.ContinueWith((t) =>
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine(t.Result + "come on.");
    });
    task.Start();
    Console.ReadLine();
}

TaskContinuationOptions

static void Main(string[] args)
{
    Task task = new Task(() =>
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    });
    task.ContinueWith((t) =>
    {
        Console.WriteLine("OnlyOnRanToCompletion");
    }, TaskContinuationOptions.OnlyOnRanToCompletion);
    task.Start();
    Console.ReadLine();
}

所有(任一)任务完成后继续

Task.Factory.ContineWhenAll()
Task.Factory.ContineWhenAny()
Task<TCType>.Factory.ContinueWhenAll<TAType>()
Task<TCType>.Factory.ContinueWhenAny<TAType>()

取消任务

System.Threading.CancellationTokenSource

static void Main(string[] args)
{
    CancellationTokenSource cts = new CancellationTokenSource();
    Task task = new Task(() =>
    {
        Thread.Sleep(3 * 1000);
        Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread);
    }, cts.Token);
    task.ContinueWith((t) =>
    {
        Console.WriteLine("OnlyOnCanceled");
    }, TaskContinuationOptions.OnlyOnCanceled);
    task.Start();
    //cts.Cancel();
    Console.ReadLine();
}

任务异常

无返回值,抓不到异常

try // 无返回值 try/catch 不管卵用
{
    Task task = new Task(() =>
    {
        throw new Exception("error");
    });
    task.ContinueWith((t) =>
    {
        Console.WriteLine(t.Exception.InnerException.Message);
    }, TaskContinuationOptions.OnlyOnFaulted); // 这样可以抓到异常
    task.Start();
}
catch (Exception ex)
{
    Console.WriteLine("无返回值:" + ex.Message);
}

有返回值,读取 Result

try // 有返回值,在读取 Result 时,如果任务异常,会向外抛出来
{
    Task<string> task = new Task<string>(() =>
    {
        throw new Exception("error");
        return "girls";
    });
    task.Start();
    Console.WriteLine(task.Result);
}
catch (AggregateException ex)
{
    Console.WriteLine("有返回值:" + ex.InnerException.Message);
}

任务嵌套

(1)父子任务绑定
TaskCreationOptions.AttachedToParent
父完成必须子完成,父报告子异常
(2)不绑定
我一般创建子任务,不绑定,但子任务必须处理异常并确保完成。

任务调度

System.Threading.Tasks.TaskScheduler

【默认任务调度器,使用线程池线程】

TaskScheduler.FromCurrentSynchronizationContext()

【解决在UI线程操作控件】

上一篇下一篇

猜你喜欢

热点阅读