zoukankan      html  css  js  c++  java
  • C#多线程编程のTask(任务全面解析)

    Task是.NET4.0加入的,跟线程池ThreadPool的功能类似,用Task开启新任务时,会从线程池中调用线程,而Thread每次实例化都会创建一个新的线程。

     我们可以说Task是一种基于任务的编程模型。它与thread的主要区别是,它更加方便对线程进程调度和获取线程的执行结果。

    Task类和Task<TResult>类
    前者接收的是Action委托类型
    后者接收的是Func<TResult>委托类型

    任务和线程的区别:

    1、任务是架构在线程之上的,也就是说任务最终还是要抛给线程去执行。

    2、任务跟线程不是一对一的关系,比如开10个任务并不是说会开10个线程,这一点任务有点类似线程池,但是任务相比
    线程池有很小的开销和精确的控制。

    一、Task的创建

    1、直接创建

    var task1 = new Task(() =>
    {
             Console.WriteLine("Begin");
             System.Threading.Thread.Sleep(5000);
             Console.WriteLine("Finish");
       });
    Console.WriteLine("Before start:" + task1.Status);
    task1.Start();

    2、工厂创建

    Task.Factory.StartNew(()={
    
    });

    3、4.5以后Run运行

    Task.Run(()=>{
    
    });

    4、一种方便获取返回值的方式

    static void Main(string[] args) 
            { 
                var tcs = new TaskCompletionSource<int>(); 
                new Thread(() => { 
                    Thread.Sleep(5000); 
                    int i = Enumerable.Range(1, 100).Sum(); 
                    tcs.SetResult(i); }).Start();//线程把运行计算结果,设为tcs的Result。 
                  Task<int> task = tcs.Task; 
                  Console.WriteLine(task.Result); //此处会阻塞,直到匿名线程调用tcs.SetResult(i)完毕 
            } 

    二、细节解释

    看下面代码:

    namespace WpfApplication6
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
    
            public MainWindow()
            {
                InitializeComponent();
                ConsoleManager.Show();//打开控制台窗口  
            }
    
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                Console.WriteLine("主线程启动");
                Task task = Task.Run(() => {
                    Thread.Sleep(1500);
                    Console.WriteLine("task启动");
                });
                Thread.Sleep(300);
                task.Wait();
                Console.WriteLine("主线程结束");
            }
    
        }
    }
    

      

    结果:

    分析:

    开启新任务的方法:Task.Run()或者Task.Factory.StartNew(),开启的是后台线程

    要在主线程中等待后台线程执行完毕,可以使用Wait方法(会以同步的方式来执行)。不用Wait则会以异步的方式来执行。

    thread和Task的区别,thread new多少个就会创建多少个线程,而task是利用线程池中的线程。

    task<TResult>就是有返回值的Task,TResult就是返回值类型。示例:

            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                Console.WriteLine("主线程开始");
                //返回值类型为string
                Task<string> task = Task<string>.Run(() => {
                    Thread.Sleep(2000);
                    return Thread.CurrentThread.ManagedThreadId.ToString();
                });
                //会等到task执行完毕才会输出;
                Console.WriteLine(task.Result);
                Console.WriteLine("主线程结束");
            }
    

     

    通过task.Result可以取到返回值,若取值的时候,后台线程还没执行完,则会等待其执行完毕!

    简单提一下:

    Task任务可以通过CancellationTokenSource类来取消。

    三、Task的其他方法

    Task.Wait();    //阻塞当前线程
    Task.WaitAll(); //阻塞当前线程直到所有的任务执行完毕
    Task.WaitAny(); //阻塞当前线程直到有任意一个任务执行完毕
    
    
    Task.ContinueWith(
    task=>{
    
    });              //执行完上一个任务后继续执行,并将上一个任务(包括结果)传递给下一个代码块
    
    
    一种是使用GetAwaiter方法。GetAwaiter方法返回一个TaskAwaiter结构,该结构有一个OnCompleted事件,只需对
    
    OnCompleted事件赋值,即可在完成后调用该事件。 
    
    static void Main(string[] args) 
            { 
                Task<int> Task1 = Task.Run<int>(() => { return Enumerable.Range(1, 100).Sum(); }); 
                var awaiter = Task1.GetAwaiter(); 
                awaiter.OnCompleted(() => 
                { 
                    Console.WriteLine("Task1 finished"); 
                    int result = awaiter.GetResult(); 
                    Console.WriteLine(result); // Writes result 
                }); 
                Thread.Sleep(1000); 
            } 

    四、任务的中断

                var tokenSource = new CancellationTokenSource();
                var token = tokenSource.Token;
                var task = Task.Factory.StartNew(() =>
                {
                    for (var i = 0; i < 1000; i++)
                    {
                        System.Threading.Thread.Sleep(1000);
                        if (token.IsCancellationRequested)
                        {
                            Console.WriteLine("Abort mission success!");
                            return;
                        }
                    }
                }, token);
    
                //注册cancel后要执行的代码
                token.Register(() =>
                {
                    Console.WriteLine("Canceled");
                });
                Console.WriteLine("Press enter to cancel task...");
                Console.ReadKey();
                //调用取消
                tokenSource.Cancel();

    五、任务的中断取消

                var tokenSource = new CancellationTokenSource();
                var token = tokenSource.Token;
                var task = Task.Factory.StartNew(() =>
                {
                    for (var i = 0; i < 1000; i++)
                    {
                        System.Threading.Thread.Sleep(1000);
                        if (token.IsCancellationRequested)
                        {
                            Console.WriteLine("Abort mission success!");
                            return;
                        }
                    }
                }, token);
    
                //注册cancel后要执行的代码
                token.Register(() =>
                {
                    Console.WriteLine("Canceled");
                });
                Console.WriteLine("Press enter to cancel task...");
                Console.ReadKey();
                //调用取消
                tokenSource.Cancel();

    六、异常处理

    异常处理;
    对于某些匿名的Task(通过 Task.Run方法生成的,不调用wait,也不关心是否运行完成),某些情况下,记录它们的异
    
    常错误也是有必要的。这些异常称作未观察到的异常(unobserved exceptions)。可以通过订阅一个全局的静态事件
    
    TaskScheduler.UnobservedTaskException来处理这些异常。只要当一个Task有异常,并且在被垃圾回收的时候,才会触
    
    发这一个事件。如果Task还处于被引用状态,或者只要GC不回收这个Task,这个UnobservedTaskException事件就不会被
    
    触发
    GC.Collect();
    GC.WaitForPendingFinalizers();

    七、Task的状态


    Created:表示默认初始化任务,但是“工厂创建的”实例直接跳过。

    WaitingToRun: 这种状态表示等待任务调度器分配线程给任务执行。

    RanToCompletion:任务执行完毕。

     

  • 相关阅读:
    redis-LinkedList
    Jedis(java操作redis数据库技术)
    jquery判断表单内容是否为空
    jQuery单选框的回显
    使用jQuery重置(reset)表单的方法
    BootstrapValidator 解决多属性被同时校验问题
    模态框被遮罩层遮挡
    python 高阶函数
    python 函数式编程
    python 生成器
  • 原文地址:https://www.cnblogs.com/xietianjiao/p/7429742.html
Copyright © 2011-2022 走看看