• 多线程编程学习笔记——线程池(一)


     接上文 多线程编程学习笔记——线程同步(一)

     接上文 多线程编程学习笔记——线程同步(二)

      接上文 多线程编程学习笔记——线程同步(三)

          创建多线程操作是非常昂贵的,所以每个运行时间非常短的操作,创建多线程进行操作,可能并不能提高效率,反而降低了效率。

          如果你有非常多的执行时间非常短的操作,那么适合作用线程池来提高效率,而不是自行创建多线程。

          线程池,就是我们先分配一些资源到池子里,当我们需要使用时,则从池子中获取,用完了,再放回池子里。

         .NET中的线程池是受CLR管理的,TheadTool类有一个QueueUserWorkItem静态方法,这个静态方法接受一个委托,代表用户自定义的一个异步操作,在这个方法被调用之后,委托会进入到内部队列中,如果池中没有线程,则创建一个工作线程,把第一个委托放入工作线程。如果继续放入委托,则池创建新的工作线程,直到工作线程数量达到上限。这时再放入委托,则不会创建新的工作线程,而是在队列中等待,直到有空闲的工作线程。

           当线程池中所有操作都完成,而且没有新任务操作时,线程池会释放长时间不用的资源。

           注意:放入线程池中的操作需要的时间要短,不要把需要长时间运行的操作放入线程池中,或阻塞工作线程。这将导致性能问题和非常难以调用的问题。

                     在ASP.NET中使用线程池要当心,ASP.NET中的线程池是一个共用线程池,如果线程池中的工作线程都用完了,则会造成WEB服务器对正常的HTTP请求无法提供服务。

    一、     线程池中调用委托

     1.代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading; 
    
    namespace ThreadPoolDemo
    {
     
    
        public delegate string ThreadPoolRun(out int threadId);
        class Program
        {  
    
            static void Main(string[] args)
            {
    
                Console.WriteLine("开始测试线程池-委托。。。");
                int threadId = 0;
                ThreadPoolRun poolDele = RunThread;
                var t = new Thread(() => RunThread(out threadId));
                t.Start();
                t.Join();
                Console.WriteLine("线程ID {0} ",threadId);
                IAsyncResult r = poolDele.BeginInvoke(out threadId, Callback, "在线程池中同步调用回调函数");
                string result = poolDele.EndInvoke(out threadId, r);
                Console.WriteLine("线程池中工作线程ID :{0}", threadId);
                Console.WriteLine("返回结果:{0}",result); 
    
                Thread.Sleep(2000);
                Console.Read(); 
    
            }
    
            private static void  Callback(IAsyncResult r)
            {
    
                Console.WriteLine("开始调用回调函数。。。");
                Console.WriteLine("回调函数此时的状态 :{0}",r.AsyncState);
                Console.WriteLine("调用此回调函数的线程是否在线程池 :{0}", Thread.CurrentThread.IsThreadPoolThread);
                Console.WriteLine("调用此回调函数的线程在线程池在的ID :{0}", Thread.CurrentThread.ManagedThreadId);
            }
    
            private static string RunThread(out int threadId)
            {
                Console.WriteLine("开始工作。。。");       
    
                Console.WriteLine("调用此回调函数的线程是否在线程池 :{0}", Thread.CurrentThread.IsThreadPoolThread);
                Thread.Sleep(TimeSpan.FromSeconds(2));
                threadId = Thread.CurrentThread.ManagedThreadId;
                return string.Format("此线程在线程池在的ID :{0}", threadId);
            }
        }
    }
    
     

    2.程序执行结果如下图。

     

           上面的程序运行时,我们首先创建线程来执行委托操作,然后调用委托的BeginInvoke来执行回调方法,这个回调函数会在异步操作完成之后会被调用,并且会把一个自定义的值传给这个回调函数,最后我们会得到一个实现了IAsyncResult接口的result对象,当线程池的工作线程在进行工作时,允许我们继续其他操作。我们可以轮询result对象的IsCompleted属性,确定操作是否完成。也可以调用EndInvoke将IAsyncResult传给委托参数。

     

    二、     线程池中放入异步操作

     1.代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading; 
    
    namespace ThreadPoolDemo
    { 
        class Program
        {   
    
            static void Main(string[] args)
            {
                Console.WriteLine("开始测试线程池-QueueUserWorkItem。。。");
                const int x = 1;
                const int y = 2;
                string workState = "工作状态 2"; 
    
                ThreadPool.QueueUserWorkItem(AsyncOper);
                Thread.Sleep(1000);
                ThreadPool.QueueUserWorkItem(AsyncOper,"同步状态");
                Thread.Sleep(1000);
    
                ThreadPool.QueueUserWorkItem(status => {
                    Console.WriteLine("操作状态 {0} ", status);
                    Console.WriteLine("线程池中工作线程ID :{0}", Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(TimeSpan.FromSeconds(2));
                },"工作状态");
     
    
                ThreadPool.QueueUserWorkItem(_ => {
                    Console.WriteLine("操作结果x+y= {0} ,{1}", x+y,workState);
                    Console.WriteLine("线程池中工作线程ID :{0}", Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(TimeSpan.FromSeconds(2));
                }, "工作状态"); 
    
                Thread.Sleep(2000);
                Console.Read();
            }
    
            private static void  AsyncOper(object status)
            {
                Console.WriteLine("操作状态 :{0} ",status??"null");
    
                Console.WriteLine("工作线程在线程池在的ID :{0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(2000);
            }  
    
        }
    }
    
     

    2.执行结果如下。程序执行了两次。

           程序首先定义了一个AsyncOper方法,然后使用QueueUserWorkItem将这个方法放入线程池中,然后再次放入一个AsyncOper方法,不过这次给方法调用传一个对象。

           代码中的调用Thread.sleep方法,是为了让线程池中的工作线程为新操作重用。请注意打印出来的ThradId,如果ThreadID一样则证明两个操作重用了同一个工作线程。

     

  • 相关阅读:
    PHP+MySQL
    Appstore排名前十的程序员应用软件
    架构师的平凡之路
    程序员,如何三十而立?
    不懂技术也可以轻松开发一款APP
    php语法学习:轻松看懂PHP语言
    你真的了解软件测试行业吗?
    十个程序员必备的网站推荐
    从更高点看软件开发的侧重点
    php如何实现文件下载
  • 原文地址:https://www.cnblogs.com/chillsrc/p/7803384.html
Copyright © 2020-2023  润新知