VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > VB.net教程 >
  • VB.net学习笔记(三十)认识线程池(2)

  •  
    StObj2.inarg2 = "String Param2 of task 2"
  •  
    '进程中只有一个Threadpool,且成员多为共享,故不必单独为其实例化对象,直接用类。
  •  
    ThreadPool.QueueUserWorkItem(New Threading.WaitCallback(AddressOf Taskl), StObj1)
  •  
    ThreadPool.QueueUserWorkItem(New Threading.WaitCallback(AddressOf Task2), StObj2)
  •  
    Console.Read()
  •  
    End Sub
  •  
    End Module
  •         说明:任务1与任务2通过线程池逐个激活(反正不让任务线程空闲),传递给委托方法的对象都被转了定义的ObjState类型。              

     

           例:理解定时触发器与开关门的关系

    
    
    1.  
      Imports System.Threading
    2.  
      Public Class vbThreadPool
    3.  
      Private Shared i As Integer = 0
    4.  
      Public Shared Sub main()
    5.  
      Dim arev As New AutoResetEvent(False) '1、自动同步
    6.  
      'Dim arev As New ManualResetEvent(False) ‘2、手动同步
    7.  
      '注册(添加)一个定时器(定时触发委托项),第一参数为开关量以确定开或关,此处False为关,受阻。
    8.  
      ThreadPool.RegisterWaitForSingleObject(arev, AddressOf workitem, Nothing, 1000, False) '3、定时触发器
    9.  
      arev.Set() '4、开关量打开(True),定时器启动(如Timer一样,每1秒调用委托方法)
    10.  
      Console.Read()
    11.  
      End Sub
    12.  
      Public Shared Sub workitem(ByVal obj As Object, ByVal signaled As Boolean)
    13.  
      i += 1
    14.  
      Console.WriteLine("Thread Pool Work Item Ivoked:" & i.ToString)
    15.  
      End Sub
    16.  
      End Class
            说明:本例代码简单,理解较难。

     

           1、理解线程池的RegisterWaitForSingleObject。           它是一个定时触发器,类似Timer控件一样,即每隔一段时间触发委托方法。 第一参数WaitHandle是一个关开量(开True,关False),它可以是手动同步ManualResetEvent或自动同步AutoResetEvent,它类似一个大门;第二参数委托方法,类似大门内关着的一匹马;第三参数state状态对象,类似给马的货物或装饰(当然也可以没有Nothing);第四参数间隔时间,类似开大门时需要间隔多久(每开一次门,就跑出一匹马,方法就执行起来了),第五参数是否只开一次门(方法也就只能执行一次,如右图)。为真,总共只执行一次;为假,不止执行一次。           因此,上面3处代码可以解释为:每隔1秒触发打开大门,马儿就跑出来,马儿无货物托运,并且总共大门不止开一次。即一直间隔1秒地去开门。

            2、理解Set           Set的目的,在AutoResentEvent自动同步中,直接打开门(True),于是下面左图或右图第一语句都是没有等1秒,就执行了。因为Set是另一个人来打开门(不是定时触发器来打开门),也即打开门有两种方式。既然门开了,马儿就直接跑出来了,还管什么定时触发器的1秒间隔?所以第一句都没有等待1秒,就直接显示出来了。 但后面语句(红箭头)都是等待了1秒才显示。这里又涉及到手动同步(ManualResetEvent)或自动同步(AutoResetEvent)的区别:         若是用的1处的自动同步(AutoResetEvent),它就类似自动门一样,打开(Set为真)后,跑出一匹马,然后大门会自动关上(为假),所以这里定时触发器的间隔时间就体现出来了:每隔一秒去开大门,跑出马后会自动关上大门,所以后面每隔一秒会显示信息。          若是用的2处的手动同步(ManualResetEvent),情况就不一样的,大门不是自动大门,打开(Set其为True)后不会自动关门(False)。如果用了4处的开大门,大门不会再关闭,大大地敞开,于是马儿一匹接一匹的向外跑,于是信息就无间隔的连续一直显示下去。定时触发器中的时间间隔就不会起作用。          本来定时触发器也有自动关门的作用,因为没有开也就没有与之对应的关(因为开是别人做的),所以它也只有干瞪眼看着一匹接一匹的马儿跑。如果我们注释掉1处使用2处语句,同时注释掉4处,就会发现:第一句也会间隔1秒(因为没人去开门,所以定时触发器来开门),然后,后面也是每隔一秒显示(因为定时触发器自已开门,也会自动去关门)。                 
    五、在.NET中的可伸缩性  
        Windows 操作系统管理着如何将线程分配给处理器,同时,触发任何进程会自动启动一个线程。.NET Framework对处理器分配不提供细粒度的控制,它宁愿让操作系统控制调度,因为与CLR相比,处理器提供更多的载入信息。然而,它还是对整个进程运行于哪个处理器提供了一些控制措施。但是这适用于进程中的所有线程,选择哪些处理器来处理超出了我们的话题。

         如果只有一个线程(即主线程),那么线程中的每个任务都将运打在相同的处理器上。然而,如果创建一个新的线程,那么操作系统将安排线程将在哪个处理器上执行。系统在作出这个判断时会消耗一些处理器资源,所以对于那些小的任务而言,这种消耗通常不值得,因为执行这些任务的时间几乎和判断由哪个处理器来执行线程的时间一样。

         然而,随着Windows版本的延续,这种分配占用的时间越来越少,同时对于除最细微的任务之外的事情而言,当使用线程时,您将发现通过创建新线程来执行任务将提高系统性能。这也只有在对称多处现器(symmetric multi-processor, SMP)系统中您才能看到线程的真正优点,因为所有的处理器都会被充分用于分配承担应用程序的负荷。  
        

          通用线程池管理器类的设计       以前创建线程的方法过于松散自由,现在线程池又过于僵硬呆板。下面创建一个线程池管理类,它维护指定数量线程的线程池,这些线程用于请求的应用程序。这样既可以在代码中更加容易控制这些线程,同时在实例化线程对象时更快地执行线程。简单地说,就是综合两者的优点。

          代码较长,逻辑图有点类似下面(引用别人的图),只是少了一部分超时的判断。                   

            提示:右击关键词,可以选择“转到定义”(迅速到定义处)或“转到实现”(迅速到实现处),工具栏左端面有一个“后退”,可迅速回到前一个代码定位处。

            首先添加一个新的类(管理器类):

    
    
      Imports System.Threading
    
      Imports System.Text
    
      Namespace GenThreadPool '通用线程池管理
    
      Public Interface IThreadPool 'ThreadPool接口,用于GenThreadPoolImpl类
    
      Sub AddJob(jobToRun As Thread) '添加作业
    
      Function GetStats() As Stats '获取状态
    
      End Interface
    
    
    
      Public Class GenThreadPoolImpl
    
      Implements IThreadPool
    
      Private m_maxThreads As Integer '最多线程
    
      Private m_minThreads As Integer '最少线程
    
      Private m_maxIdleTime As Integer '最长空闲时间(超时删除对应线程)
    
      Private Shared m_debug As Boolean '是否调试
    
      Private m_pendingJobs As ArrayList '等待的作业量(数组形式,以便列队进入线程池)
    
      Private m_availableThreads As ArrayList '可用线程数
    
    
    
      Public Property PendingJobs() As ArrayList
    
      Get
    
      Return m_pendingJobs
    
      End Get
    
      Set
    
      m_pendingJobs = Value
    
      End Set
    
      End Property
    
      Public Property AvailableThreads() As ArrayList
    
      Get
    
      Return m_availableThreads
    
      End Get
    
      Set
    
      m_availableThreads = Value
    
      End Set
    
      End Property
    
      Public Property Debug() As Boolean
    
      Get
    
      Return m_debug
    
      End Get
    
      Set
    
      m_debug = Value
    
      End Set
    
      End Property
    
      Public Property MaxIdleTime() As Integer
    
      Get
    
      Return m_maxIdleTime
    
      End Get
    
      Set
    
      m_maxIdleTime = Value
    
      End Set
    
      End Property
    
      Public Property MaxThreads() As Integer
    
      Get
    
      Return m_maxThreads
    
      End Get
    
      Set
    
      m_maxThreads = Value
    
      End Set
    
      End Property
    
      Public Property MinThreads() As Integer
    
      Get
    
      Return m_minThreads
    
      End Get
    
      Set
    
      m_minThreads = Value
    
      End Set
    
      End Property
    
    
    
      Public Sub New() '默认构造。只允许1个线程在池中,0.3秒后销毁
    
      m_maxThreads = 1
    
      m_minThreads = 0
    
      m_maxIdleTime = 300
    
      m_pendingJobs = ArrayList.Synchronized(New ArrayList) '对数组同步包装(仍为数组),因为这样上
    
      m_availableThreads = ArrayList.Synchronized(New ArrayList) '锁才线程安全,以防其它线程同时进行修改。
    
      m_debug = False
    
      End Sub
    
      Public Sub New(ByVal maxThreads As Integer, ByVal minThreads As Integer, ByVal maxIdleTime As Integer)
    
      '构造函数,用3个参数实例化
    
      m_maxThreads = maxThreads
    
      m_minThreads = minThreads
    
      m_maxIdleTime = maxIdleTime
    
      m_pendingJobs = ArrayList.Synchronized(New ArrayList)
    
      m_availableThreads = ArrayList.Synchronized(New ArrayList)
    
      m_debug = False
    
      InitAvailableThreads()
    
      End Sub
    
      Private Sub InitAvailableThreads() '初始化线程池,分别进入池中
    
      If m_maxThreads > 0 Then
    
      For i As Integer = 1 To m_maxThreads
    
      Dim t As New Thread(AddressOf (New GenPool(Me, Me)).Run)
    
      Dim e As New ThreadElement(t)
    
      e.Idle = True
    
      m_availableThreads.Add(e)
    
      Next
    
      End If
    
      End Sub
    
      Public Sub New(ByVal maxThreads As Integer, ByVal minThreads As Integer, ByVal maxIdleTime As Integer, ByVal debug As Boolean)
    
      '构造函数,用4个参数实例化,增加调试参数
    
      m_maxThreads = maxThreads
    
      m_minThreads = minThreads
    
      m_maxIdleTime = maxIdleTime
    
      m_pendingJobs = ArrayList.Synchronized(New ArrayList)
    
      m_availableThreads = ArrayList.Synchronized(New ArrayList)
    
      m_debug = debug
    
      InitAvailableThreads()
    
      End Sub
    
      Public Sub AddJob(ByVal job As Thread) Implements IThreadPool.AddJob '向池中添加作业
    
      If job Is Nothing Then
    
      Return '作业不存在,退出
    
      End If
    
    
    
      SyncLock Me '锁定GenThreadPoolImpl,防止其它线程来添加或删除作业
    
      m_pendingJobs.Add(job) '将作业添加到 ArrayList 的结尾处。
    
      Dim index As Integer = FindFirstIdleThread() '空闲可用线程的索引
    
      If m_debug Then
    
      Console.WriteLine("First Idle Thread Is " & index.ToString)
    
      End If
    
    
    
      If index = -1 Then '-1无空闲线程,故需创建新的线程
    
      If m_maxThreads = -1 Or m_availableThreads.Count <       m_maxThreads Then
    
      '池中无线程,或在用(有效)线程还未达最大线程数限制--->创建线程
    
      If m_debug Then
    
      Console.WriteLine("Creating a New thread")
    
      End If
    
    
    
      Dim t As New Thread(AddressOf (New GenPool(Me, Me)).Run)
    
      Dim e As New ThreadElement(t) '帮助类,提供线程额外属性
    
      e.Idle = False
    
      e.GetMyThread.Start() '线程添加到ArrayList数组前先激发
    
    
    
      Try '添加
    
      m_availableThreads.Add(e)
    
      Catch ex As OutOfMemoryException
    
      Console.WriteLine("Out Of memory: " & ex.ToString)
    
      Thread.Sleep(3000)
    
      m_availableThreads.Add(e)
    
      Console.WriteLine("Added Job again")
    
      End Try
    
      Return
    
      End If
    
    
    
      If m_debug Then
    
      Console.WriteLine("No Threads Available...” & GetStats.ToString)
    
      End If
    
      Else '池中找到有空的线程
    
      Try
    
      If m_debug Then
    
      Console.WriteLine("Using an existing thread...")
    
      End If
    
    
    
      CType(m_availableThreads(index), ThreadElement).Idle = False '标注忙碌
    
      SyncLock CType(m_availableThreads(index), ThreadElement).GetMyThread()
    
      Monitor.Pulse(CType(m_availableThreads(index), ThreadElement).GetMyThread())
    
      End SyncLock
    
      Catch ex As Exception
    
      Console.WriteLine(("Error while reusing thread " & ex.Message))
    
      If m_debug Then
    
      Console.WriteLine("Value of index Is " & index.ToString)
    
      Console.WriteLine("Size of available threads Is " & m_availableThreads.Count.ToString)
    
      Console.WriteLine("Available Threads Is " & m_availableThreads.IsSynchronized.ToString)
    
      End If
    
      End Try
    
      End If
    
      End SyncLock
    
      End Sub
    
      Public Function GetStats() As Stats Implements IThreadPool.GetStats '池中状态
    
      Dim statsInstance As New Stats()
    
      statsInstance.MaxThreads = m_maxThreads
    
      statsInstance.MinThreads = m_minThreads
    
      statsInstance.MaxIdleTime = m_maxIdleTime '最大空闲时间
    
      statsInstance.PendingJobs = m_pendingJobs.Count '等待的作业量
    
      statsInstance.NumThreads = m_availableThreads.Count '有效线程数
    
      statsInstance.JobsInProgress = m_availableThreads.Count - FindIdleThreadCount() '正在处理的作业量
    
      Return statsInstance
    
      End Function
    
      Public Function FindIdleThreadCount() As Integer '遍历有效线程,返回空闲线程数
    
      Dim idleThreads As Integer = 0
    
      For i As Integer = 0 To m_availableThreads.Count - 1
    
      If CType(m_availableThreads(i), ThreadElement).Idle Then '根据帮助类中的空闲标志Idle来统计
    
      idleThreads += 1
    
      End If
    
      Next
    
      Return idleThreads
    
      End Function
    
      Public Function FindFirstIdleThread() As Integer '遍历,找      到第一个空闲线程,就立即返回其索引
    
      For i As Integer = 0 To m_availableThreads.Count - 1
    
      If CType(m_availableThreads(i), ThreadElement).Idle Then
    
      Return i
    
      End If
    
      Next
    
      Return -1
    
      End Function
    
      Public Function FindThread() As Integer '查找当前线程的位置(索引号),失败为-1(说明池中无线程)
    
      For i As Integer = 0 To m_availableThreads.Count - 1
    
      If CType(m_availableThreads(i), ThreadElement).GetMyThread.Equals(Thread.CurrentThread) Then
    
      Return i
    
      End If
    
      Next
    
      Return -1
    
      End Function
    
      Public Sub RemoveThread() '移除线程
    
      For i As Integer = 0 To m_availableThreads.Count - 1
    
      If CType(m_availableThreads(i), ThreadElement).GetMyThread.Equals(Thread.CurrentThread) Then
    
      m_availableThreads.RemoveAt(i)
    
      Exit Sub
    
      End If
    
      Next
    
      End Sub
    
      End Class
    
      Public Class GenPool '执行线程类(执行完毕后,过了指定超时时限,将自动从池中删除)
    
      Private m_lock As Object '锁定对象
    
      Private m_gn As GenThreadPoolImpl
    
      Public Sub New(lock_ As Object, gn As GenThreadPoolImpl)
    
      m_lock = lock_
    
      m_gn = gn
    
      End Sub
    
      Public Sub Run() '循环运行并检测是否过期
    
      Dim job As Thread
    
      While True '无限循环,一直检查池中状态
    
      While True
    
      SyncLock m_lock
    
      If m_gn.PendingJobs.Count = 0 Then '后续无作业进来
    
      Dim index As Integer = m_gn.FindThread() '取当前线程索引号
    
      If index = -1 Then '无作业,池中也无线程,退出
    
      Exit Sub
    
      End If '无作业,新的线程设为空闲
    
      CType(m_gn.AvailableThreads(index), ThreadElement).Idle = True
    
      Exit While
    
      End If
    
      job = CType(m_gn.PendingJobs(0), Thread) '有作业,取出(从原作业数组中删除)
    
      m_gn.PendingJobs.RemoveAt(0)
    
      End SyncLock
    
      job.Start() '作业执行启动
    
      End While
    
      Try '无后续作业
    
      SyncLock Me
    
      If m_gn.MaxIdleTime = -1 Then '池中无空闲线程,阻塞等待
    
      Monitor.Wait(Me)
    
      Else
    
      Monitor.Wait(Me, m_gn.MaxIdleTime)
    
      End If
    
      End SyncLock
    
      Catch
    
      End Try
    
      SyncLock m_lock
    
      If m_gn.PendingJobs.Count = 0 Then '无等待的作业(没有新的作业进来)
    
      If m_gn.MinThreads <> -1 And m_gn.AvailableThreads.Count > m_gn.MinThreads Then
    
      m_gn.RemoveThread() '池中线程不空,且有效线程大于最小线程,删除线程
    
      Return
    
      End If
    
      End If
    
      End SyncLock
    
      End While
    
      End Sub
    
      End Class
    
    
    
      Public Class ThreadElement '对应线程的线程帮助类(以例为之设计空闲标志,获取引用)
    
      Private m_idle As Boolean '空闲线程标志
    
      Private m_thread As Thread
    
      Public Sub New(th As Thread)
    
      m_thread = th
    
      m_idle = True '初始化即为空闲
    
      End Sub
    
      Public Property Idle() As Boolean '设置或获取线程空闲标志
    
      Get
    
      Return m_idle
    
      End Get
    
      Set
    
      m_idle = Value
    
      End Set
    
      End Property
    
      Public Function GetMyThread() As Thread '取得原线程
    
      Return m_thread
    
      End Function
    
      End Class
    
    
    
      Public Structure Stats '状态统计
    
      Public MaxThreads As Integer
    
      Public MinThreads As Integer
    
      Public MaxIdleTime As Integer
    
      Public NumThreads As Integer
    
      Public PendingJobs As Integer '列队等待的作业量
    
      Public JobsInProgress As Integer '正在处理的作业量
    
      Public Overrides Function ToString() As String '提取状态
    
      Dim sb As New StringBuilder("MaxThreads = ", 107) '容量大小107字符
    
      sb.Append(MaxThreads)
    
      sb.Append(ControlChars.Lf & "MinThreads=" & MinThreads)
    
      sb.Append(ControlChars.Lf & "MaxIdleTime=" & MaxIdleTime)
    
      sb.Append(ControlChars.Lf & "PendingJobs=" & PendingJobs)
    
      sb.Append(ControlChars.Lf & "JobsInProgress=" & JobsInProgress)
    
      Return sb.ToString
    
      End Function
    
      End Structure
    
      End Namespace
           然后,完成主程序代码,用来测试:
    
      Imports System.Threading
    
      Namespace TestGenThreadPool
    
      Public Class TestPerformance
    
      Public count As Integer
    
      Private m_lock As New Object()
    
    
    
      Public Sub New(pool As GenThreadPool.IThreadPool, times As Integer)
    
      Console.WriteLine("Performance using Pool [in ms]: ")
    
      count = 0
    
      Dim start As Long = Now.Millisecond
    
      Console.WriteLine("Start Time For Job Is " & Now)
    
      Dim i As Integer
    
      For i = 0 To times - 1
    
      Dim tl As New Thread(AddressOf (New Job(Me)).Run)
    
      pool.AddJob(tl)
    
      Next
    
    
    
      While True
    
      SyncLock m_lock
    
      If count = times Then
    
      Exit While
    
      End If
    
      End SyncLock
    
    
    
    
    
      Try
    
      Thread.Sleep(5000)
    
      Catch
    
      End Try
    
      End While
    
    
    
      Console.WriteLine(" " & (Now.Millisecond - start).ToString)
    
      Console.WriteLine("End Time for Job is " & Now.ToString)
    
      Console.WriteLine("Performance using no Pool [in ms]: ")
    
      count = 0
    
      start = Now.Millisecond
    
      Console.WriteLine("Start Time for JobThread is " & Now.ToString)
    
      For i = 0 To times - 1
    
      Dim jt As New Thread(AddressOf (New JobThread(Me)).Run)
    
      jt.Start()
    
      Next
    
    
    
      While True
    
      SyncLock m_lock
    
      If count = times Then
    
      Exit While
    
      End If
    
      End SyncLock
    
      Try
    
      Thread.Sleep(5000)
    
      Catch
    
      End Try
    
      End While
    
      Console.WriteLine(" " & (Now.Millisecond - start).ToString())
    
      Console.WriteLine("End Time for JobThread is ” & Now.ToString)
    
      End Sub
    
      NotInheritable Class JobThread
    
      Private m_lock As New Object()
    
      Private tpf As TestPerformance
    
      Public Sub New(tpf_ As TestPerformance)
    
      tpf = tpf_
    
      End Sub
    
      Public Sub Run()
    
      SyncLock m_lock
    
      tpf.count += 1
    
      End SyncLock
    
      End Sub
    
      End Class
    
      NotInheritable Class Job
    
      Private m_lock As New Object()
    
      Private tpf As TestPerformance
    
    
    
      Public Sub New(tpf_ As TestPerformance)
    
      tpf = tpf_
    
      End Sub
    
      Public Sub Run()
    
      SyncLock m_lock
    
      tpf.count += 1
    
      End SyncLock
    
      End Sub
    
      End Class
    
      End Class
    
      Class TestPool
    
      Private Shared i As Integer = 0
    
      Private j As Integer = 0
    
      Public Sub Run()
    
      i += 1
    
      j = i
    
      Console.WriteLine("Value of i in run is {0} ", j)
    
      End Sub
    
      Public Shared Sub Main(args() As String)
    
      Dim tp = New GenThreadPool.GenThreadPoolImpl(1000, 1000, 300, True)
    
      Dim i As Integer
    
      For i = 0 To 99 '添加作业到线程池管理器
    
      Dim td1 As New TestPool
    
      Dim t1 As New Thread(AddressOf td1.Run)
    
      Dim td2 As New TestPool
    
      Dim t2 As New Thread(AddressOf td2.Run)
    
      Dim td3 As New TestPool
    
      Dim t3 As New Thread(AddressOf td3.Run)
    
      Dim td4 As New TestPool
    
      Dim t4 As New Thread(AddressOf td4.Run)
    
      Dim td5 As New TestPool
    
      Dim t5 As New Thread(AddressOf td5.Run)
    
      Dim td6 As New TestPool
    
      Dim t6 As New Thread(AddressOf td6.Run)
    
      Dim td7 As New TestPool
    
      Dim t7 As New Thread(AddressOf td7.Run)
    
      Dim td8 As New TestPool
    
      Dim t8 As New Thread(AddressOf td8.Run)
    
      Dim td9 As New TestPool
    
      Dim t9 As New Thread(AddressOf td9.Run)
    
      Dim td10 As New TestPool
    
      Dim t10 As New Thread(AddressOf td10.Run)
    
      Dim td11 As New TestPool
    
      Dim t11 As New Thread(AddressOf td11.Run)
    
      tp.AddJob(t1)
    
      tp.AddJob(t2)
    
      tp.AddJob(t3)
    
      tp.AddJob(t4)
    
      tp.AddJob(t5)
    
      tp.AddJob(t6)
    
      tp.AddJob(t7)
    
      tp.AddJob(t8)
    
      tp.AddJob(t9)
    
      tp.AddJob(t10)
    
      tp.AddJob(t11)
    
      Next
    
      Dim td12 As New TestPool
    
      Dim t12 As New Thread(AddressOf td12.Run)
    
      tp.AddJob(t12)
    
      Dim p As New TestPerformance(tp, 1000)
    
      End Sub
    
      End Class
    
      End Namespace


    1.  
    2.  
          结果较长,同时播放视频时,就可明显感觉到视频有点卡顿,说明CPU有点忙不过来了:)                      
    
    相关教程
    关于我们--广告服务--免责声明--本站帮助-友情链接--版权声明--联系我们       黑ICP备07002182号