我是一个很好的设计,可以在Windows服务中使用任务作为工作线程,还是我们应该更好地坚持使用Thread.Start()?也许甚至没有将工作者作为LongRunning启动,如果它们大部分处于空闲状态,由FileSystemWatcher事件触发并使用Take()关闭BlockingCollections进行处理。
Public Class FileWatcherService
Private _watchPaths As New List(Of String) From {"x:\Dir1","x:\Dir2","y:\Dir1", ...}
Private _workers As New List(Of Task)
Private _cancellationTokenSource As New CancellationTokenSource()
Private _cancellationToken As CancellationToken = _cancellationTokenSource.Token
Protected Overrides Sub OnStart(ByVal args() As String)
For Each path In _watchPaths
_workers.Add(
Task.Factory.StartNew(
Sub()
Dim fileProcessor As New FileProcessor
fileProcessor.StartWorking(path, _cancellationToken)
End Sub, TaskCreationOptions.LongRunning, _cancellationToken))
Next
End Sub
Protected Overrides Sub OnStop()
_cancellationTokenSource.Cancel()
Task.WaitAll(_workers.ToArray)
End Sub
End Class
Class FileProcessor
Private _newFiles As New BlockingCollection(Of String)
Sub _fileWatcher_Created(sender As Object, e As FileSystemEventArgs)
_newFiles.Add(e.FullPath, _cancellationToken)
End Sub
Async Function ProcessNewFiles() As Task
Do
Await ProcessFile(_newFiles.Take(_cancellationToken))
Loop
End Function
End Class
修改
上面的方法在空闲时不释放工作线程,因为Take()上的块。 以下解决方案使用ActionBlock而不是BlockingCollection。这个解决方案不会在闲置时查看新文件时使用线程。我旋转线程来处理新文件并在完成后释放它们。而且我不再使用LongRunning启动顶级工作任务。
Class FileProcessor
Private _newFilesActionBlock As New ActionBlock(Of String)(
Async Function(filePath)
Await ProcessFile(filePath)
End Function,
New ExecutionDataflowBlockOptions With {
.CancellationToken = _cancellationToken})
Sub _fileWatcher_Created(sender As Object, e As FileSystemEventArgs)
Handles __fileWatcher.Created
_newFilesActionBlock.Post(e.FullPath)
End Sub
'...
结束班
答案 0 :(得分:2)
TPL是非常受欢迎的.NET框架。它使您的线程代码更易于使用且更易读。它允许您使您的Windows服务(或任何其他线程代码)多线程,而无需实例化和处理线程池和单个线程。
我在我的Windows服务中使用TPL,它对我很有用,在大多数情况下,我肯定会建议使用TPL而不是经典的线程池。
话虽如此,有一些极少数情况下您仍然希望自己处理线程池,但根据您的代码片段,您似乎并不需要为此烦恼......