• 多线程系列(三):线程池基础


    目录:

    • 为什么要使用线程池
    • 简单的线程池操作
    • 执行上下文
    • 协作式取消

    一、为什么要使用线程池:线程池概念理解

    备注:线程池中的线程是后台线程。

    1、为什么会有线程池?

      因为创建线程和销毁线程相对来说需要消耗大量的时间和资源。 太多的线程会浪费内存。

           操作系统需要在线程间来回切换,线程过多,有损性能。

    2、线程池是什么?

      线程池就是一个可持续性发展的线程集合,线程池内部维护着一个消息队列。

      当一条方法名引用追加到线程池的队列中,线程池会提取当前项,派发给线程池中空闲的线程。

    3、线程池创建线程策略?

    • 如果线程池中没有线程,就创建一个线程。
    • 如果并发的请求数过多,且请求速度超出线程池处理速度,就会创建额外线程。
    • 如果线程完成任务,不会销毁,会进入空闲状态,等待下个请求的响应。
    • 如果在一定的时间内没有接收到请求,超度空闲,就会自己醒来,终止自己,释放资源。

    二、简单的线程池操作

    我们上面提到过,线程池内维护的了一个消息队列,方法引用追加到队列中,线程池中的线程从队列中取出等待执行。

    [SecuritySafeCritical]
     public static bool QueueUserWorkItem(WaitCallback callBack);
    [SecuritySafeCritical]
     public static bool QueueUserWorkItem(WaitCallback callBack, object state);

    委托:

     [ComVisible(true)]
      public delegate void WaitCallback(object state);

    所以,一个是参数为null,一个是需要传递实参的委托。要使用以上方式向队列中添加工作项,其实是将方法引用添加到队列中

    1、我们定义一个符合 WaitCallback 规则的委托 一个参数且没有返回值

       public static void WorkerFun(object flag)
       {
                Console.WriteLine("【WorkerFun】 doing ........");
                for (int index = 10; index > 0; index--)
                {
                    Console.WriteLine("     {0}s", index);
                    Thread.Sleep(2000);
                }
          Console.WriteLine("【WorkerFun】end.");
        }

    2、我们使用线程池进行异步调用

    public void Run(string args)
    {
        Console.WriteLine("【Main】doing......");
        if (ThreadPool.QueueUserWorkItem(WorkerFun))
        {
            Console.WriteLine("Add pool success");
        }
        Console.WriteLine("【Main】sleep 5s.");
      
    Thread.Sleep(5000);
    Console.WriteLine("【Main】end.");
    }

    运行结果:

    主线程执行完毕,子线程自动关闭。所以说,线程池中的线程都是后台线程,优先级比较低。

    二、执行上下文

    1、为什么要有执行上下文 ?

    线程在执行代码时,会受到上下文的影响。

    上下文会从初始线程流向辅助线程,这样这整个线程使用相同的安全设置和宿主设置。

    同样,辅助线程可以使用初始线程的逻辑上下文。

    namespace System.Threading
        //执行上下文
      public sealed class ExecutionContext : IDisposable, ISerializable
        {
            //从当前线程捕获执行上下文 
            [SecuritySafeCritical]
            public static ExecutionContext Capture();  
            //是否取消了执行上下文的流动        
            public static bool IsFlowSuppressed(); 
            //恢复执行上下文在异步线程之间的流动        
            public static void RestoreFlow();       
            //在当前线程上的指定执行上下文中运行某个方法
            [SecurityCritical]
            public static void Run(ExecutionContext executionContext, ContextCallback callback, object state);        
            //取消执行上下文在异步线程之间的流动  
            [SecurityCritical]
            public static AsyncFlowControl SuppressFlow(); 
            //创建当前执行上下文的副本           
            [SecuritySafeCritical]
            public ExecutionContext CreateCopy(); 
            [SecuritySafeCritical]
            public void Dispose();       
            [SecurityCritical]
            public void GetObjectData(SerializationInfo info, StreamingContext context);
        }

    通过执行上下文我们来控制上下文的流动。

    CallContext.LogicalSetData("Name", "sc");
    //默认允许上下文进行流动
    ThreadPool.QueueUserWorkItem(state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name")));
    //现在禁止流动
    ExecutionContext.SuppressFlow();
    ThreadPool.QueueUserWorkItem(state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name")));
    //恢复流动
    ExecutionContext.RestoreFlow();
    Console.ReadKey();

    运行:第一行允许流动;第二行禁止流动

    Name=sc
    Name=

    三、协作式取消和超时

    需要取消的模式必须显示支持取消

    //通知 System.Threading.CancellationToken,告知其应被取消
    public sealed class CancellationTokenSource : IDisposable

    CancellationTokenSource  管理 着取消相关的状态.

    所谓协作式,首先我自己要支持取消,接收信号后任务终止。

    private static void Count(System.Threading.CancellationToken token, int countto)
    {
        for (int count = 0; count < countto; count++)
        {
            Console.WriteLine("index:{0}", count);
            if (token.IsCancellationRequested)
            {
                Console.WriteLine("Count is cancelled  {0}",count);
                break;
            }
        }
    }

     主线程中,接收协作式取消命令,子线程检测到信号后,主动停止。

    public void Run(string args)
    {         
        System.Threading.CancellationTokenSource cts = new CancellationTokenSource();
        //开启线程
        ThreadPool.QueueUserWorkItem(state => Count(cts.Token, 10000000));
        Console.WriteLine("Press <Enter> to cancel the operation");
        Console.ReadLine();
        cts.Cancel();
        Console.ReadLine();
    }

     运行结果:主线程发出回车信号,子线程检测到信号后结束任务。

  • 相关阅读:
    【转】Nginx open_file_cache模块 文件描述符缓存
    缓冲区溢出二:从缓冲区溢出到获取反弹shell实例
    英文文法学习笔记(18)代名词
    英文文法学习笔记(17)特殊构句
    英文文法学习笔记(19)时态
    小知识:RMAN基于某个具体时间点的恢复示例
    小知识:NFS卡死问题处理
    英文文法学习笔记(20)时态的一致及叙述法
    英文文法学习笔记(21)连接词
    小知识:如何从图片中提取文字
  • 原文地址:https://www.cnblogs.com/sunchong/p/8654899.html
Copyright © 2020-2023  润新知