zoukankan      html  css  js  c++  java
  • 多线程编程学习笔记——线程池(一)

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

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

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

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

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

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

         .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一样则证明两个操作重用了同一个工作线程。

     

  • 相关阅读:
    self 和 super 关键字
    NSString类
    函数和对象方法的区别
    求两个数是否互质及最大公约数
    TJU Problem 1644 Reverse Text
    TJU Problem 2520 Quicksum
    TJU Problem 2101 Bullseye
    TJU Problem 2548 Celebrity jeopardy
    poj 2586 Y2K Accounting Bug
    poj 2109 Power of Cryptography
  • 原文地址:https://www.cnblogs.com/chillsrc/p/7803384.html
Copyright © 2011-2022 走看看