• C# 多线程线程池( 一 )


     

    我们将在这里进一步讨论一些.NET类,以及他们在多线程编程中扮演的角色和怎么编程。它们是:

      System.Threading.ThreadPool

      System.Threading.Timer

      如果线程的数目并不是很多,而且你想控制每个线程的细节诸如线程的优先级等,使用Thread是比较合适的;但是如果有大量的线程,考虑使用线程池应该更好一些,它提供了高效的线程管理机制来处理多任务。 对于定期的执行任务Timer类是合适的;使用代表是异步方法调用的首选。

    System.Threading.ThreadPool Class

      当你创建应用程序时,你应该认识到大部分时间你的线程在空闲的等待某些事件的发生(诸如按下一个键或侦听套节子的请求)。毫无疑问的,你也会认为这是绝对的浪费资源。

      如果这里有很多的任务需要完成,每个任务需要一个线程,你应该考虑使用线程池来更有效的管理你的资源并且从中受益。线程池是执行的多个线程集合,它允许你添加以线程自动创建和开始的任务到队列里面去。使用线程池使得你的系统可以优化线程在CPU使用时的时间碎片。但是要记住在任何特定的时间点,每一个进程和每个线程池只有一个一个正在运行的线程。这个类使得你的线程组成的池可以被系统管理,而使你的主要精力集中在工作流的逻辑而不是线程的管理。

      当第一次实例化ThreadPool类时线程池将被创建。它有一个默认的上限,即每处理器最多可以有25个,但是这个上限是可以改变的。这样使得处理器不会闲置下来。如果其中一个线程等待某个事件的发生,线程池将初始化另外一个线程并投入处理器工作,线程池就是这样不停的创建工作的线程和分配任务给那些没有工作的在队列里的线程。唯一的限制是工作线程的数目不能超过最大允许的数目。每个线程将运行在默认的优先级和使用默认的属于多线程空间的堆栈大小空间。一旦一项工作任务被加入队列,你是不能取消的。

      请求线程池处理一个任务或者工作项可以调用QueueUserWorkItem方法。这个方法带一个WaitCallback代表类型的参数,这个参数包装了你药完成的任务。运行时自动为每一个的任务创建线程并且在任务释放时释放线程。

      下面的代码说明了如何创建线程池和怎样添加任务:

    public void afunction(object o) 
    { 
      // do what ever the function is supposed to do. 
    } 
    
    //thread entry code 
    { 
      // create an instance of WaitCallback 
      WaitCallback myCallback = new WaitCallback (afunction); 
      //add this to the thread pool / queue a task 
      ThreadPool.QueueUserWorkItem (myCallback); 
    }

      你也可以通过调用ThreadPool.RegisterWaitForSingleObject方法来传递一个System.Threading.WaitHandle,当被通知或者时间超过了调用被System.Threading.WaitOrTimerCallback包装的方法。

      线程池和基于事件的编程模式使得线程池对注册的WaitHandles的监控和对合适的WaitOrTimerCallback代表方法的调用十分简单(当WaitHandle被释放时)。这些做法其实很简单。这里有一个线程不断的观测在线程池队列等待操作的状态。一旦等待操作完成,一个线程将被执行与其对应的任务。因此,这个方法随着出发触发事件的发生而增加一个线程。

      让我们看看怎么随事件添加一个线程到线程池,其实很简单。我们只需要创建一个ManualResetEvent类的事件和一个WaitOrTimerCallback的代表,然后我们需要一个携带代表状态的对象,同时我们也要决定休息间隔和执行方式。我们将上面的都添加到线程池,并且激发一个事件:

    public void afunction(object o) 
    { 
      // do what ever the function is supposed to do. 
    } 
    
    //object that will carry the status information
    public class anObject 
    { 
    } 
    
    //thread entry code 
    { 
      //create an event object
      ManualResetEvent aevent = new ManualResetEvent (false); 
    
      // create an instance of WaitOrTimerCallback 
      WaitOrTimerCallback thread_method = new WaitOrTimerCallback (afunction); 
    
      // create an instance of anObject 
      anObject myobj = new anObject(); 
    
      // decide how thread will perform 
      int timeout_interval = 100; // timeout in milli-seconds. 
      bool onetime_exec = true; 
    
      //add all this to the thread pool. 
      ThreadPool. RegisterWaitForSingleObject (aevent, thread_method, myobj, timeout_interval, onetime_exec); 
    
      // raise the event 
      aevent.Set(); 
    }

      在QueueUserWorkItem和RegisterWaitForSingleObject方法中,线程池创建了一个后台的线程来回调。当线程池开始执行一个任务,两个方法都将调用者的堆栈合并到线程池的线程堆栈中。如果需要安全检查将耗费更多的时间和增加系统的负担,因此可以通过使用它们对应的不安全的方法来避免安全检查。就是ThreadPool.UnsafeRegisterWaitForSingleObject 和ThreadPool.UnsafeQueueUserWorkItem。

      你也可以对与等待操作无关的任务排队。 Timer-queue timers and registered wait operations也使用线程池。它们的返回方法也被放入线程池排队。

      线程池是非常有用的,被广泛的用于。NET平台上的套节子编程,等待操作注册,进程计时器和异步的I/O。对于小而短的任务,线程池提供的机制也是十分便利处于多线程的。线程池对于完成许多独立的任务而且不需要逐个的设置线程属性是十分便利的。但是,你也应该很清楚,有很多的情况是可以用其他的方法来替代线程池的。比如说你的计划任务或给每个线程特定的属性,或者你需要将线程放入单个线程的空间(而线程池是将所有的线程放入一个多线程空间),抑或是一个特定的任务是很冗长的,这些情况你最好考虑清楚,安全的办法比用线程池应该是你的选择。


    System.Threading.Timer Class

      Timer类对于周期性的在分离的线程执行任务是非常有效的,它不能被继承。

      这个类尤其用来开发控制台应用程序,因为System.Windows.Forms.Time是不可用的。比如同来备份文件和检查数据库的一致性。

      当创建Timer对象时,你药估计在第一个代理调用之前等待的时间和后来的每次成功调用之间的时间。一个定时调用发生在方法的应得时间过去,并且在后来周期性的调用这个方法。你可以适应Timer的Change方法来改变这些设置的值或者使Timer失效。当定时器Timer不再使用时,你应该调用Dispose方法来释放其资源。

      TimerCallback代表负责指定与Timer对象相关联的方法(就是要周期执行的任务)和状态。它在方法应得的时间过去之后调用一次并且周期性的调用这个方法直到调用了Dispose方法释放了Timer的所有资源。系统自动分配分离的线程。

      让我们来看一段代码看看事如何创建Timer对象和使用它的。我们首先要创建一个TimerCallback代理,在后面的方法中要使用到的。如果需要,下一步我们要创建一个状态对象,它拥有与被代理调用的方法相关联的特定信息。为了使这些简单一些,我们传递一个空参数。我们将实例化一个Timer对象,然后再使用Change方法改变Timer的设置,最后调用Dispose方法释放资源。

    // class that will be called by the Timer 
    public class WorkonTimerReq 
    { 
    
      public void aTimerCallMethod() 
      { 
        // does some work
      } 
    } 
    
    
    //timer creation block 
    { 
      //instantiating the class that gets called by the Timer. 
      WorkonTimerReq anObj = new WorkonTimerReq () ; 
    
      // callback delegate 
      TimerCallback tcallback = new TimerCallback(anObj.aTimerCallMethod) ; 
    
      // define the dueTime and period 
      long dTime = 20 ; // wait before the first tick (in ms) 
      long pTime = 150 ; // timer during subsequent invocations (in ms) 
    
      // instantiate the Timer object 
      Timer atimer = new Timer(tcallback, null, dTime, pTime) ; 
    
      // do some thing with the timer object 
    
      //change the dueTime and period of the Timer 
      dTime=100; 
      pTime=300; 
      atimer.Change(dTime, pTime) ; 
      // do some thing 
    
      atimer.Dispose() ; 
    
    }

    转自:http://wenku.baidu.com/link?url=6nMdLt1BKXGjrdN89IA95HaoyAmS7n97RN2PNJ1g36yZhNLQtyZa2shwlI0s1REDr2RKvh-kdjXGLpL2nwvZX5gzMbiEjc_fWNN65hXrMqK

     

  • 相关阅读:
    【SpringBoot】 理解SpringBoot的启动原理
    【SpringBoot】SpringBoot的基础,全面理解bean的生命周期
    【转】 Linux 命令解释(Linux基础二)
    【转】 Linux 的目录详解 (Linux基础一)
    【SpringBoot】 一种解决接口返回慢的方式
    【Jmeter基础】 Linux上运行Jmeter
    【SpingBoot】 测试如何使用SpringBoot搭建一个简单后台1
    单例模式@Singleton在测试中的运用
    性能测试基础 ---TCP通信过程的状态码与过程,以及出现错误码的分析(TIME_WAIT,CLOSE_WAIT)
    Spring5源码分析(007)——IoC篇之加载BeanDefinition总览
  • 原文地址:https://www.cnblogs.com/fangkuai/p/3662107.html
Copyright © 2020-2023  润新知