3

将任务用于 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
'...

结束类

4

1 回答 1

2

TPL 是非常受欢迎的 .NET 框架的补充。它使您的线程代码更易于使用且更具可读性。它允许您使您的 Windows 服务(或任何其他线程代码)成为多线程的,而无需实例化和处理线程池和单个线程。

我在我的 Windows 服务中使用 TPL,它对我来说非常有用,我肯定会推荐在大多数情况下使用 TPL 而不是经典线程池。

话虽如此,在一些非常罕见的情况下,您仍然希望自己处理线程池,但根据您的代码片段,您似乎并不需要为此烦恼......

于 2012-09-17T19:18:07.243 回答