你的位置:首页 > 软件开发 > ASP.net > 使用线程池而不是创建线程

使用线程池而不是创建线程

发布时间:2016-05-03 19:00:05
在我们开发程序时,若存在耗性能、高并发处理的任务时,我们会想到用多线程来处理。在多线程处理中,有手工创建线程与线程池2种处理方式,手工创建线程存在管理与维护的繁琐。.Net线程池能够帮我们完成线程资源的管理工作,使用我们专注业务处理,而不是代码的细微实现。在你创建了过多的任务,线 ...

  在我们开发程序时,若存在耗性能、高并发处理的任务时,我们会想到用多get='_blank'>线程来处理。在多线程处理中,有手工创建线程与线程池2种处理方式,手工创建线程存在管理与维护的繁琐。.Net线程池能够帮我们完成线程资源的管理工作,使用我们专注业务处理,而不是代码的细微实现。在你创建了过多的任务,线程池也能用列队把无法即使处理的请求保存起来,直至有线程释放出来。

  当应用程序开始执行重复的后台任务,且并不需要经常与这些任务交互时,使用.Net线程池管理这些资源将会让性能更佳。我们可以使用ThreadPool.QueueUserWorkItem方法来让线程池为你管理资源,将方法资源排入队列以便执行。 此方法在有线程池线程变得可用时执行。QueueUserWorkItem方法有2中重载,分别为有参数与无参数。如下列出:

使用线程池而不是创建线程

  线程池会根据正在运行的任务数量与线程池大小,被加入的任务可能会立即执行,或等待直至有空余的线程再处理。线程池由每个处理器中一定数量的就绪线程和一系列I/O读取线程组成,具体的数字因硬件与.Net版本不同而有差别,在开始向列队中插入执行的任务时,线程池可能会创建更多的线程,也可能等待有可用线程再去执行,这取决于当前内存与其他资源的可用情况。我们不需要详细明白线程池内部的具体实现,因为线程池本身就是为了降低我们的工作,并让框架帮我们分担。简而言之,线程池中的线程数量将在可用线程数据和最小化已分配但尚未使用的资源之间自动平衡。

  线程池同样也会管理线程结束后的维护工作,当任务结束后,线程并不会被销毁,而是返回到可用状态,以便执行其他任务。所有的QueueUserWorkItem使用的线程池中的线程均为后台线程,这就意味着你并不需要在应用程序推出之前手工清理资源,若是应用程序在这些后台线程还在运行时就退出了,那么系统将会停止这些后台任务,并释放所有与应用程序相关的资源。我们只要确保在应用程序退出之前停止了所有非后台线程即可。

  如下给出了3种线程的测试代码,分别为单个线程、手工线程、线程池

/// <summary>/// 测试单线程、手工线程、线程池/// </summary>public static class TestThread{  private static uint lowerBound = 0, upperBound = 1000000;  private const double tolerance = 1.0e-8;//公差  // 获得数字的平方根  private static double SquareRoot(double number)  {    double guess = 1, error = Math.Abs(guess * guess - number);    while (error > tolerance)    {      guess = (number / guess + guess) / 2;      error = Math.Abs(guess * guess - number);    }    return guess;  }  public static double SingleThread()  {    Stopwatch start = new Stopwatch();    start.Start();    for (uint i = lowerBound; i < upperBound; i++)    {      double answer = SquareRoot(i);    }    start.Stop();    return start.ElapsedMilliseconds;  }  public static double ManualThreads(int numThreads)  {    Stopwatch start = new Stopwatch();    using (AutoResetEvent e = new AutoResetEvent(false))    {      int workerThreads = numThreads;      start.Start();      for (int thread = 0; thread < numThreads; thread++)      {        Thread t = new Thread(() =>        {          for (uint i = lowerBound; i < upperBound; i++)          {            //并行计算            if (i % numThreads == thread)            {              double answer = SquareRoot(i);            }          }          //减少计数器的值          if (Interlocked.Decrement(ref workerThreads) == 0)          {            e.Set();//设置事件          }        });        t.Start();      }      //等待信号      e.WaitOne();      start.Stop();      return start.ElapsedMilliseconds;    }  }  public static string content = "线程池输出的内容";  public static double ThreadPoolThreads(int numThreads)  {    Stopwatch start = new Stopwatch();    //此处使用AutoResetEvent类,用于通知当前线程(等待的线程,即主线程)发生了什么。    using (AutoResetEvent e = new AutoResetEvent(false))//false标记为非终止状态,即任务未完成    {      int workerThreads = numThreads;      start.Start();      for (int thread = 0; thread < numThreads; thread++)      {        /*WaitCallback,回调委托,代表由系统(程序)自动执行的方法,不需要自己手动去执行。在使用QueueUserWorkItem单个参数方法时,WaitCallback委托中state参数为null;若要使用state参数进行数据处理,需要调用2个参数的QueueUserWorkItem方法。*/        ThreadPool.QueueUserWorkItem(x =>        {          Console.WriteLine(content);          for (uint i = lowerBound; i < upperBound; i++)          {            //并行计算            if (i % numThreads == thread)            {              double answer = SquareRoot(i);            }          }          //递减计数器的值,Interlocked类是连锁-互锁,为多线程共享的资源在并发时,锁定共享的资源只能同时有一个线程在执行。此处也可以使用lock(关键字)同步锁进行处          if (Interlocked.Decrement(ref workerThreads) == 0)          {            //设置事件状态为终止状态,即任务完成(告诉等待的线程不用等待,可以继续执行了)。            e.Set();          }        }, content);      }      //等待信号,阻塞当前线程(直到任务完成-即AutoResetEvent设置为终止状态,才继续执行)      e.WaitOne();      start.Stop();      return start.ElapsedMilliseconds;    }  }}

原标题:使用线程池而不是创建线程

关键词:线程

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。