多线程学习之Task

多线程学习笔记:

*进程(Process):

** 是系统中的一个基本概念。 一个正在运行的应用程序在操作系统中被视为一个进程,包含着一个运行程序所需要的资源,进程可以包括一个或多个线程 。进程之间是相对独立的,一个进程无法访问另一个进程的数据(除非利用分布式计算方式),一个进程运行的失败也不会影响其他进程的运行,Windows系统就是利用进程把工作划分为多个独立的区域的。进程可以理解为一个程序的基本边界

线程(Thread):

是进程中的基本执行单元,是操作系统分配CPU时间的基本单位 ,在进程入口执行的第一个线程被视为这个进程的主线程

多线程的优点:
  可以同时完成多个任务;可以让占用大量处理时间的任务或当前没有进行处理的任务定期将处理时间让给别的任务;可以随时停止任务;可以设置每个任务的优先级以优化程序性能。

多线程的缺点:
  1、 内存占用 线程也是程序,所以线程需要占用内存,线程越多,占用内存也越多(每个线程都需要开辟堆栈空间,多线程时有时需要切换时间片)。

2、 管理协调 多线程需要协调和管理,所以需要占用CPU时间以便跟踪线程,线程太多会导致控制太复杂。

3、 资源共享 线程之间对共享资源的访问会相互影响,必须解决争用共享资源的问题。

线程同步

是指在某一时刻只有一个线程可以访问变量 。

c#为同步访问变量提供了一个非常简单的方式,即使用c#语言的关键字Lock,它可以把一段代码定义为互斥段,互斥段在一个时刻内只允许一个线程进入执行,实际上是Monitor.Enter(obj),Monitor.Exit(obj)的语法糖。在c#中,lock的用法如下:

lock (obj) { dosomething... }

obj代表你希望锁定的对象,注意一下几点
   1. lock不能锁定空值 ,因为Null是不需要被释放的。
   2. 不能锁定string类型 ,虽然它也是引用类型的。因为字符串类型被CLR“暂留”,这意味着整个程序中任何给定字符串都只有一个实例,具有相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的所有实例。
   3. 值类型不能被lock每次装箱后的对象都不一样 ,锁定时会报错 。
   4 . 避免锁定public类型 如果该实例可以被公开访问,则 lock(this) 可能会有问题,因为不受控制的代码也可能会锁定该对象。
   推荐使用 private static readonly类型的对象,readonly是为了避免lock的代码块中修改对象,造成对象改变后锁失效。

线程异步

同步和异步主要用于修饰方法。当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法;当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务,调用者不用等待该方法执行完毕,我们称这个方法为异步方法。
  ThreadPool介绍
  ThreadPool中有若干数量的线程,如果有任务需要处理时,会从线程池中获取一个空闲的线程来执行任务,任务执行完毕后线程不会销毁,而是被线程池回收以供后续任务使用。当线程池中所有的线程都在忙碌时,又有新任务要处理时,线程池才会新建一个线程来处理该任务,如果线程数量达到设置的最大值,任务会排队,等待其他任务释放线程后再执行。线程池能减少线程的创建,节省开销。
  示例:

static void Main(string[] args)
        {
            for (int i = 1; i <=10; i++)
            {
                //ThreadPool执行任务
                ThreadPool.QueueUserWorkItem(new WaitCallback((obj) => {
                    Console.WriteLine($"第{obj}个执行任务");
                }),i);
            }
            Console.ReadKey();
        }

ThreadPool相对于Thread来说可以减少线程的创建,有效减小系统开销;但是ThreadPool不能控制线程的执行顺序,我们也不能获取线程池内线程取消/异常/完成的通知,即我们不能有效监控和控制线程池中的线程。

Task创建

Task拥有线程池的优点,同时也解决了使用线程池不易控制的弊端,Task的创建和执行方式有如下三种:


          Task task = new Task(() =>
            {
                Thread.Sleep(100);
                Console.WriteLine($"hello, task1的线程ID为{Thread.CurrentThread.ManagedThreadId}");
            });
            task.Start();

            //2.Task.Factory.StartNew(Action action)创建和启动一个Task
            Task task2 = Task.Factory.StartNew(() =>
              {
                  Thread.Sleep(100);
                  Console.WriteLine($"hello, task2的线程ID为{ Thread.CurrentThread.ManagedThreadId}");
              });

            //3.Task.Run(Action action)将任务放在线程池队列,返回并启动一个Task
            Task task3 = Task.Run(() =>
              {
                  Thread.Sleep(100);
                  Console.WriteLine($"hello, task3的线程ID为{ Thread.CurrentThread.ManagedThreadId}");
              });

Task.Resut: 获取结果时会阻塞所有线程包括主线程,即如果task没有执行完成,会等待task执行完成获取到Result,然后执行后边的线程。
Thread.Join(): 可阻塞主线程。
Task.Wait(): 阻塞主线程表示等待task执行完毕,功能类似于thead.Join();
Task.WaitAll(Task[] tasks): 表示只有所有的task都执行完成了再解除阻塞;
Task.WaitAny(Task[] tasks): 表示只要有一个task执行完毕就解除阻塞
Task.WhenAll(Task[] tasks) 表示所有的task都执行完毕后再去执行后续的操作,
Task.WhenAny(Task[] tasks) 表示任一task执行完毕后就开始执行后续操作

Task的任务取消(CancellationTokenSource)

Task中有一个专门的类 CancellationTokenSource 来取消任务执行。
CancellationTokenSource的功能不仅仅是取消任务执行,我们可以使用 source.CancelAfter(5000) 实现5秒后自动取消任务,也可以通过 source.Token.Register(Action action) 注册取消任务触发的回调函数,即任务被取消时注册的action会被执行。

static void Main(string[] args)
        {
            CancellationTokenSource source = new CancellationTokenSource();
            //注册任务取消的事件
            source.Token.Register(() =>
            {
                Console.WriteLine("任务被取消后执行xx操作!");
            });

            int index = 0;
            //开启一个task执行任务
            Task task1 = new Task(() =>
              {
                  while (!source.IsCancellationRequested)
                  {
                      Thread.Sleep(1000);
                      Console.WriteLine($"第{++index}次执行,线程运行中...");
                  }
              });
            task1.Start();
            //延时取消,效果等同于Thread.Sleep(5000);source.Cancel();
            source.CancelAfter(5000);
            Console.ReadKey();
        }

参考原作:https://www.cnblogs.com/Mask71/p/12094860.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值