美文网首页.NET多线程
.NET多线程(四)任务

.NET多线程(四)任务

作者: 万州大牛 | 来源:发表于2017-03-12 19:31 被阅读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线程操作控件】

    相关文章

      网友评论

        本文标题:.NET多线程(四)任务

        本文链接:https://www.haomeiwen.com/subject/ecjgbttx.html