线程池简述+两种传统的异步编程模式

1.线程池简述

  首先我们要明确一点,编程中讲的线程与平时我们形容CPU几核几线程中的线程是不一样的,CPU线程是指逻辑处理器,比如4核8线程,讲的是这个cpu有8个逻辑处理器,可以同时处理8个线程。我们编程中讲的线程在计算机中可以有许多许多,如下图所示,这些线程并不是都在执行状态,他们平时大部分都是休眠状态,只有进程去调用他们时,他们才是激活状态。线程通过他们的ThreadState(线程状态)属性告诉CPU,它们是否需要被CPU去执行。比如有2000个线程,其中有20个线程的线程状态属性为“待执行”,那么CPU的逻辑处理器就会在空闲时根据线程的优先级去执行线程(4核8线程的CPU最多同时执行8个线程),正在执行的线程状态属性会被改为“正在执行”,当该线程执行结束后,其线程状态属性会被改为“休眠”,此时CPU就不会再理他们。

  • 什么是C#线程池呢?

  顾名思义,线程池就是放线程的池子,我们在运行任意.NET程序时,都会在CLR(你可以把他理解为软件后台)生成一个线程池,池内已经new出来了很多的Thread实例,我们在需要型线程的时候不用自己new,直接从池子里拿现成的Thread实例即可,用完后这个Thread实例会被自动还回线程池!线程池中的线程对象数量与我们计算机有关,具体数字我忘了,反正是CPU核心越多,逻辑处理器越多,那么线程池的线程就越多,我们一般不用管池内有多少个线程(一般是足够你用的),即使线程池的线程都在被占用状态,此时你再从线程池拿线程时,线程池也会自动new新增一个线程给你。

  • 为什么要使用C#线程池呢?

  因为new一个Thread是比较耗费资源并且执行较慢的行为,比如我们在一个1000次的循环中,每个循环都要new出一个Thread进行某些任务的处理,会使得任务执行缓慢,并且计算机内存蹭蹭上涨。我们不如直接在每次循环中从线程池获取一个线程,用完再放回去,这样的处理不仅速度快,对内存也没有任何影响。

2.线程池的使用(简单讲解)

  因为线程池在.NET4.0后新出的Task类及Async与await关键字出现后就不怎么用了,这里仅仅简单讲一讲线程池的用法。

  直接看代码:

复制代码
        //创建一个线程执行的方法         public static void DoSth(object obj)         {             //输出当前执行线程的ID             Console.WriteLine((string)obj+Thread.CurrentThread.ManagedThreadId);             Thread.Sleep(500);//线程睡眠5秒         }                  static void Main(string[] args)         {             for (int i = 0; i < 1000; i++)             {                 //-----------------非简写方式-----------------                 //WaitCallback是一个委托(有一个Object类型参数,无返回值)                 WaitCallback callBack = new WaitCallback(DoSth);                 //QueueUserWorkItem只支持WaitCallback作为参数,第二个参数是传入委托方法的参数                 ThreadPool.QueueUserWorkItem(callBack, "abc");                  //-----------------lambda简写方式-----------------                 ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>                 {                     //输出当前执行线程的ID                     Console.WriteLine((string)obj + Thread.CurrentThread.ManagedThreadId);                     Thread.Sleep(500);//线程睡眠5秒                 }),"abc");             }         }
复制代码

  这里补充讲一下ThreadPool.QueueUserWorkItem方法,这个方法从作用上讲是从线程池获取一个新线程去执行一个委托方法。但是为什么它的方法名是QueueUserWorkItem而非GetValueableThread这样的名称呢?因为QueueUserWorkItem的实质其实是将委托方法传入线程池的一个任务队列中,线程池中的空闲线程负责去对任务队列中的线程进行执行,这才是它实质的运行逻辑。

  注意:ThreadPool.QueueUserWorkItem只能接受“有且只有一个Object类型,且无返回值的委托方法”。

3.异步编程简介

  同步编程:我们平时不用多线程的时候基本就是同步编程模式,代码从上到下依次执行。

  关于什么是异步编程模式,首先我们看一段代码:

复制代码