有没有办法知道线程池中的活动线程正在执行什么任务?
Is there a way to know what task if being performed by the active threads in the ThreadPool?
背景...
我有一个 Windows 服务,里面有很多组件,所有组件都 运行 按计划进行。每个组件处理文件,但根据文件在我们系统中的当前状态对文件执行特定任务。这些组件当前在服务的每个组件内为每个正在处理的文件创建线程 (System.Threading.Thread)。
组件 1 可能正在从 FTP 站点下载文件。
组件 2 可能正在将文件解压缩到硬盘。
组件 3 可能正在解密硬盘上的文件。
组件 4 可能正在将文件从一个地方复制或移动到另一个地方。
目前,每个组件在一个新的线程中开始其特定于组件的任务,每个正在处理的文件。这对我们来说效果很好,但随着系统和公司的发展,它变得越来越难以管理。我正在研究 ThreadPool (System.Threading.ThreadPool),以实现更简单的线程管理和更好的整体资源管理。
这是一个简化的当前设计...
'send a message that the component task has begun
Comms.ComponentStatus(ComponentID, Running)
For Each f As File
Dim t As New Thread(AddressOf processFile)
t.Start(f)
lst.Add(t)
Next
'some list checking to see if all threads in list are done
Do Until lst has no active threads
Loop
'all threads complete so the component task is complete
Comms.ComponentStatus(ComponentID, Complete)
我的困境...
我创建了一个仪表板,用于接收有关每个组件和正在执行的任务的实时消息 (.Net Remoting)。跟踪信息、异常信息以及最重要的组件任务整体的开始和结束。在我目前的设计中,我会发出任务已经开始的消息,为每个要处理的文件创建线程并跟踪创建的线程。我查看为该任务创建的所有线程,当它们全部完成时,我会发出任务已完成的消息。这对我们来说非常有效。使用 ThreadPool 设计,我的所有组件都将从进程范围的线程池中提取线程,允许系统管理它们,但不允许我知道每个组件中哪些线程正在用于哪些任务,因此不允许我知道组件的任务何时完成。
快速查看 .Net 的 ThreadPool 并没有告诉我可以确定池中的哪些活动线程正在执行哪些任务。有人有解决方案或建议吗?提前致谢。
'this only returns a bool telling me the requested task will be performed
ThreadPool.QueueUserWorkItem
'this only returns to me a number of threads available for queue
ThreadPool.GetAvailableThreads()
我决定做的是创建一个 Class 来保存有关正在执行的任务的信息,包括组件 ID、任务 ID 和线程计数。每当任务运行时,它都会在组件级别(Class 级别)创建此对象的实例。这使我能够在组件级别隔离线程数。当它在 ThreadPool 中对线程进行排队时,它会增加对象中的线程计数器。当所有线程都排队后,它会等待线程计数器从 return 变为 0,从而将任务标记为完成。每次线程的委托完成处理(线程完成)时,线程计数器都会递减。我设置了一个包罗万象的时间跨度以脱离线程计数循环,以防发生不可预见的事情。快速代码和测试从概念上向我展示了它确实有效。我将继续编码和测试,如果发现任何导致更改的结果,我将 post 放在这里。
这是我对线程跟踪对象的初步概述。
Public Class TaskTracker : Implements IDisposable
Public ReadOnly Property ComponentID As Integer = 0
Public ReadOnly Property TaskUID As Guid = Guid.Empty
Public ReadOnly Property ThreadCount As Integer = 0
''' <summary>
''' Create a new instance of the TaskTracker object.
''' </summary>
''' <param name="ComponentID">The ID of the Component this object belongs to.</param>
''' <param name="TaskUID">The UID of the Task in question.</param>
Public Sub New(ComponentID As Integer, TaskUID As Guid)
Try
_ComponentID = ComponentID
_TaskUID = TaskUID
_ThreadCount = 0
Catch ex As Exception
Log.Save(Log.Types.Error, ComponentID, TaskUID, ex.Message, ex.StackTrace)
End Try
End Sub
''' <summary>
''' Increment the internal thread count property by the amount in the value provided.
''' </summary>
''' <param name="Value">The amount to increment the thread count by.</param>
Public Sub IncrementThreadCount(Optional Value As Integer = 1)
Try
_ThreadCount += Value
Catch ex As Exception
Log.Save(Log.Types.Error, ComponentID, TaskUID, ex.Message, ex.StackTrace)
End Try
End Sub
''' <summary>
''' Decrement the internal thread count property by the amount in the value provided.
''' </summary>
''' <param name="Value">The amount to decrement the thread count by.</param>
Public Sub DecrementThreadCount(Optional Value As Integer = 1)
Try
If _ThreadCount > 0 Then
_ThreadCount -= Value
Else
_ThreadCount = 0
End If
Catch ex As Exception
Log.Save(Log.Types.Error, ComponentID, TaskUID, ex.Message, ex.StackTrace)
End Try
End Sub
Private disposedValue As Boolean
Protected Overridable Sub Dispose(disposing As Boolean)
If Not disposedValue Then
If disposing Then
End If
_ComponentID = 0
_TaskUID = Guid.Empty
_ThreadCount = 0
End If
disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
End Sub
End Class
这是它的(缩写)实现...
Private Shared taskTrack As TaskTracker = Nothing
Public Shared Function Start() As ResultPackage
Try
TaskUID = Guid.NewGuid()
taskTrack = New TaskTracker(ComponentID, TaskUID)
'let any listeners know the task has started
Comms.ComponentStatus(ComponentID, True)
'mark the start time of the total task
compStart = Now
Log.Save(Log.Types.Trace, ComponentID, TaskUID, _ClassName & " Started", "Successful start of the " & _ClassName & " component.")
For Each cli As ClientMaster In ClientMaster.GetList(True)
'inner try/catch so that we can continue to process clients even if one errors
Try
ThreadPool.QueueUserWorkItem(AddressOf processClient, cli)
Log.Save(Log.Types.Trace, ComponentID, TaskUID, "Client Thread Queued", "Thread queued for Client [" & cli.ClientName & "].")
taskTrack.IncrementThreadCount()
Catch ex As Exception
Log.Save(Log.Types.Error, ComponentID, TaskUID, ex.Message, ex.StackTrace)
End Try
Next
Do Until taskTrack.ThreadCount = 0 'or some timespan has been reached for a catchall
Thread.Sleep(500)
Loop
Comms.ComponentStatus(ComponentID, False)
'mark the end time of the total task
compEnd = Now
Log.Save(Log.Types.Trace, ComponentID, TaskUID, _ClassName, "Successful end of the " & _ClassName & " component.")
Log.Save(Log.Types.Trace, ComponentID, TaskUID, _ClassName & " Task Time", _ClassName & " task took " & FriendlyTimeSpan(DateDiff(DateInterval.Second, compStart, compEnd)) & " to complete.")
Comms.ComponentMessage(ComponentID, "Task Duration: " & FriendlyTimeSpan(DateDiff(DateInterval.Second, compStart, compEnd)))
Catch ex As Exception
resPack.Result = ResultPackage.Results.Fail
resPack.Alerts.Add(New ResultPackage.Alert("Exception in Start()", ex))
Log.Save(Log.Types.Error, ComponentID, TaskUID, ex.Message, ex.StackTrace)
Throw
End Try
Return resPack
End Function
Private Shared Sub processClient(Client As ClientMaster)
'do work
'decrease the thread counter since this task is complete
taskTrack.DecrementThreadCount()
End Sub
背景...
我有一个 Windows 服务,里面有很多组件,所有组件都 运行 按计划进行。每个组件处理文件,但根据文件在我们系统中的当前状态对文件执行特定任务。这些组件当前在服务的每个组件内为每个正在处理的文件创建线程 (System.Threading.Thread)。
组件 1 可能正在从 FTP 站点下载文件。
组件 2 可能正在将文件解压缩到硬盘。
组件 3 可能正在解密硬盘上的文件。
组件 4 可能正在将文件从一个地方复制或移动到另一个地方。
目前,每个组件在一个新的线程中开始其特定于组件的任务,每个正在处理的文件。这对我们来说效果很好,但随着系统和公司的发展,它变得越来越难以管理。我正在研究 ThreadPool (System.Threading.ThreadPool),以实现更简单的线程管理和更好的整体资源管理。
这是一个简化的当前设计...
'send a message that the component task has begun
Comms.ComponentStatus(ComponentID, Running)
For Each f As File
Dim t As New Thread(AddressOf processFile)
t.Start(f)
lst.Add(t)
Next
'some list checking to see if all threads in list are done
Do Until lst has no active threads
Loop
'all threads complete so the component task is complete
Comms.ComponentStatus(ComponentID, Complete)
我的困境...
我创建了一个仪表板,用于接收有关每个组件和正在执行的任务的实时消息 (.Net Remoting)。跟踪信息、异常信息以及最重要的组件任务整体的开始和结束。在我目前的设计中,我会发出任务已经开始的消息,为每个要处理的文件创建线程并跟踪创建的线程。我查看为该任务创建的所有线程,当它们全部完成时,我会发出任务已完成的消息。这对我们来说非常有效。使用 ThreadPool 设计,我的所有组件都将从进程范围的线程池中提取线程,允许系统管理它们,但不允许我知道每个组件中哪些线程正在用于哪些任务,因此不允许我知道组件的任务何时完成。
快速查看 .Net 的 ThreadPool 并没有告诉我可以确定池中的哪些活动线程正在执行哪些任务。有人有解决方案或建议吗?提前致谢。
'this only returns a bool telling me the requested task will be performed
ThreadPool.QueueUserWorkItem
'this only returns to me a number of threads available for queue
ThreadPool.GetAvailableThreads()
我决定做的是创建一个 Class 来保存有关正在执行的任务的信息,包括组件 ID、任务 ID 和线程计数。每当任务运行时,它都会在组件级别(Class 级别)创建此对象的实例。这使我能够在组件级别隔离线程数。当它在 ThreadPool 中对线程进行排队时,它会增加对象中的线程计数器。当所有线程都排队后,它会等待线程计数器从 return 变为 0,从而将任务标记为完成。每次线程的委托完成处理(线程完成)时,线程计数器都会递减。我设置了一个包罗万象的时间跨度以脱离线程计数循环,以防发生不可预见的事情。快速代码和测试从概念上向我展示了它确实有效。我将继续编码和测试,如果发现任何导致更改的结果,我将 post 放在这里。
这是我对线程跟踪对象的初步概述。
Public Class TaskTracker : Implements IDisposable
Public ReadOnly Property ComponentID As Integer = 0
Public ReadOnly Property TaskUID As Guid = Guid.Empty
Public ReadOnly Property ThreadCount As Integer = 0
''' <summary>
''' Create a new instance of the TaskTracker object.
''' </summary>
''' <param name="ComponentID">The ID of the Component this object belongs to.</param>
''' <param name="TaskUID">The UID of the Task in question.</param>
Public Sub New(ComponentID As Integer, TaskUID As Guid)
Try
_ComponentID = ComponentID
_TaskUID = TaskUID
_ThreadCount = 0
Catch ex As Exception
Log.Save(Log.Types.Error, ComponentID, TaskUID, ex.Message, ex.StackTrace)
End Try
End Sub
''' <summary>
''' Increment the internal thread count property by the amount in the value provided.
''' </summary>
''' <param name="Value">The amount to increment the thread count by.</param>
Public Sub IncrementThreadCount(Optional Value As Integer = 1)
Try
_ThreadCount += Value
Catch ex As Exception
Log.Save(Log.Types.Error, ComponentID, TaskUID, ex.Message, ex.StackTrace)
End Try
End Sub
''' <summary>
''' Decrement the internal thread count property by the amount in the value provided.
''' </summary>
''' <param name="Value">The amount to decrement the thread count by.</param>
Public Sub DecrementThreadCount(Optional Value As Integer = 1)
Try
If _ThreadCount > 0 Then
_ThreadCount -= Value
Else
_ThreadCount = 0
End If
Catch ex As Exception
Log.Save(Log.Types.Error, ComponentID, TaskUID, ex.Message, ex.StackTrace)
End Try
End Sub
Private disposedValue As Boolean
Protected Overridable Sub Dispose(disposing As Boolean)
If Not disposedValue Then
If disposing Then
End If
_ComponentID = 0
_TaskUID = Guid.Empty
_ThreadCount = 0
End If
disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
End Sub
End Class
这是它的(缩写)实现...
Private Shared taskTrack As TaskTracker = Nothing
Public Shared Function Start() As ResultPackage
Try
TaskUID = Guid.NewGuid()
taskTrack = New TaskTracker(ComponentID, TaskUID)
'let any listeners know the task has started
Comms.ComponentStatus(ComponentID, True)
'mark the start time of the total task
compStart = Now
Log.Save(Log.Types.Trace, ComponentID, TaskUID, _ClassName & " Started", "Successful start of the " & _ClassName & " component.")
For Each cli As ClientMaster In ClientMaster.GetList(True)
'inner try/catch so that we can continue to process clients even if one errors
Try
ThreadPool.QueueUserWorkItem(AddressOf processClient, cli)
Log.Save(Log.Types.Trace, ComponentID, TaskUID, "Client Thread Queued", "Thread queued for Client [" & cli.ClientName & "].")
taskTrack.IncrementThreadCount()
Catch ex As Exception
Log.Save(Log.Types.Error, ComponentID, TaskUID, ex.Message, ex.StackTrace)
End Try
Next
Do Until taskTrack.ThreadCount = 0 'or some timespan has been reached for a catchall
Thread.Sleep(500)
Loop
Comms.ComponentStatus(ComponentID, False)
'mark the end time of the total task
compEnd = Now
Log.Save(Log.Types.Trace, ComponentID, TaskUID, _ClassName, "Successful end of the " & _ClassName & " component.")
Log.Save(Log.Types.Trace, ComponentID, TaskUID, _ClassName & " Task Time", _ClassName & " task took " & FriendlyTimeSpan(DateDiff(DateInterval.Second, compStart, compEnd)) & " to complete.")
Comms.ComponentMessage(ComponentID, "Task Duration: " & FriendlyTimeSpan(DateDiff(DateInterval.Second, compStart, compEnd)))
Catch ex As Exception
resPack.Result = ResultPackage.Results.Fail
resPack.Alerts.Add(New ResultPackage.Alert("Exception in Start()", ex))
Log.Save(Log.Types.Error, ComponentID, TaskUID, ex.Message, ex.StackTrace)
Throw
End Try
Return resPack
End Function
Private Shared Sub processClient(Client As ClientMaster)
'do work
'decrease the thread counter since this task is complete
taskTrack.DecrementThreadCount()
End Sub