零基础快速入门C#并发编程:计算限制的异步操作(1) -- CLR线程池基础

39 阅读4分钟

进程当中的很多线程,即使几乎不占用 CPU 的占用率,但却依然再运行:

  • 大量线程在等待某个 IO 的操作;
  • 等待某些计时器的操作;

3.1 CLR 线程池基础

为什么需要线程池 因为有大量的 IO 等待操作,系统当中会存在大量的线程同时存在于系统当中。因此操作系统对于这些线程的创建啊和销毁会消耗大量的内存;

  • 此时可以使用线程池来管理所有这些线程:线程池是应用程序能够使用的线程的集合;
  • 每一个 CLR 对应一个单独的线程池;

什么是线程池

  • 线程池执行机制:操作请求队列
    • 记录项
      • 线程池在内部维护了一个操作请求队列,应用执行某一个异步操作时,就调用某个方法,将一个记录项追加到线程池的队列当中;
      • 线程池的代码将记录项的队列当中提取记录项,将此记录项派发给线程池线程;
    • 创建线程
      • 当线程池中没有线程或者没有足够的线程时,线程池将会创建一个线程;
      • 线程销毁:在线程结束后,线程返回线程池,进入空闲状态 ;
      • 因为线程不直接创建或者销毁自身,因此可以减少额外的性能损失;
    • 线程池中线程数量
      • 线程数量是启发式的动态变化;
      • 线程池只可以容纳少量线程;
      • 在需要利用多处理器、超线程处理器和多核处理器时,线程池也可也容纳更多的线程;

将计算限制操作加入到线程池 通过调用 ThreadPool 类中的方法,可以将计算限制操作放到线程池的队列中:

static Boolen QueueUserWorkItem(WaitCallback callBack);
static Boolen QueueUserWorkItem(WaitCallback callBack,Object state);
  • 功能描述
    • 使用 QueueUserWorkItem 方法,可以将一个 WorkItem 加入到线程池当中;
  • 参数
    • QueueUserWorkItem 中传入的参数,必须匹配 System.Threading.WaitCallback 委托类型;
  • WaitCallback 参数
delegate void WaitCallback(Object state);

3.2 执行上下文

什么是执行上下文 每个线程都关联了一个执行上下文(一种数据结构);

  • 包含内容
    • 安全设置
      • 压缩栈
      • Thread 的 Principal 属性
      • Windows 身份
    • 宿主设置
      • 逻辑调用上下文数据
  • 执行上下文流动
    • 当一个线程使用另一个线程执行时,当前线程的执行上下文将会流向(即复制到)目标切换线程;
    • 意义:
      • 保证了初始线程的逻辑调用上下文存储的任何数据都可以适用于辅助线程;

控制执行上下文:ExecutionContextSystem.Threading 中有 ExecutionContext 类,可以用于控制线程的执行上下文;

  • 作用:可以用于组织执行上下文的流动,进而提高应用程序的性能;
    • 注:部分客户端线程无法调用标注了 [SecurityCritical]SuppressFlow 方法;
public sealed class ExecutionContext : IDisposable,ISerializable
{
	[SecurityCritical]
	public static AsyncFlowControl SuppressFlow();
	public static void RestoreFlow();
	public static Boolen IsFlowSuppressed();
}

示例:阻止执行上下文流动

public static void Main()
{
	CallContext.LogicalSetData("Name","Jeffrey");
	ThreadPool.QueueUserWorkItem
	(
		state -> Console.WriteLine("Name={0}",CallContext.LogicalSetData ("Name"));
	);
	//以上是正常执行的版本 

	//这部分代码将阻止Main方法中的线程池流动;
	ExecutionContext.SuppressFlow();
	ThreadPool.QueueUserWorkItem
	(
		state -> Console.WriteLine("Name={0}",CallContext.LogicalSetData ("Name"));
	);

	//这是恢复Main方法的线程中的上下六流动;
	ExecutionContext.RestoreFlow();
}

3.3 协作式取消和超时

标准取消操作模式 无论是要执行操作的代码,还是试图取消操作的代码,都必须使用这部分的类型;

  • .NET 提供了标准的取消操作模式,并且此模式是协作式的:要取消的操作必须是显示的支持取消;
  • 对于长时间运行的计算限制操作,很需要为其提供取消的支持;

CancellationToKenSource 类

  • 类的作用:管理和取消相关的所有状态; 类定义:
public sealed class CancellationToKenSource : IDisposable
{
	public CancellationToKenSource();
	public void Dispose();
	
	public Boolean IsCancellationRequested
	{
		get;
	}

	public CancellationToken 
	{
		get;
	}

	//内部调用Cancel并传递false
	public void Cancel();
	public void Cancel(Boolean throwOnFirstException);
}

CancellationToken 结构

  • 作用:包含和取消状态相关的状态、语句;
    • CancellationToken 实例是轻量级的值类型,包含单个私有字段,表示对于 CancellationTonekSource 的引用;
  • IsCancellationRequested 属性
    • 在计算限制的循环语句当中,可以通过定期调用此属性,知道循环应当合适终止;