3

Windows サービスのワーカー スレッドに Tasks を使用するのは適切な設計でしょうか? それとも、Thread.Start() を使用したほうがよいでしょうか? ワーカーがほとんどアイドル状態で、FileSystemWatcher イベントによってトリガーされ、Take() off BlockingCollections を使用して処理を行う場合は、ワーカーを LongRunning として開始することさえできないかもしれません。

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() でブロックされるため、アイドル時にワーカー スレッドが解放されません。次のソリューションでは、BlockingCollection の代わりに ActionBlock を使用します。このソリューションは、新しいファイルをぼんやりと監視している間、スレッドを消費しません。スレッドを起動して新しいファイルを処理し、完了したら解放します。また、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は、.NETFrameworkへの追加として歓迎されています。これにより、スレッデッドコードの操作がはるかに簡単になり、読みやすくなります。これにより、スレッドプールや個々のスレッドをインスタンス化して処理しなくても、Windowsサービス(またはその他のスレッドコード)をマルチスレッドにすることができます。

私はWindowsサービスでTPLを使用していますが、これは私にとって非常に効果的であり、ほとんどの場合、従来のスレッドプールの代わりにTPLを使用することをお勧めします。

そうは言っても、スレッドプールを自分で処理したいという非常にまれなケースがいくつかありますが、コードスニペットに基づくと、実際にはそれを気にする必要はないようです...

于 2012-09-17T19:18:07.243 に答える