Если Я выполнял ряд требований, подобных этому, тогда я хотел бы взглянуть на следующие инструменты:
Используя базовую рабочую службу. NET, есть C# template dotnet new worker -lang c# -o CSharpService
создает C# долго работающую программу. Такой же долго работающий сервис может быть создан в F #.
Для создания проекта необходимо следующее:
dotnet new console -lang F# -o FsharpService
cd FsharpService
dotnet add package Microsoft.Extensions.Hosting
dotnet add package Microsoft.Extensions.Hosting.WindowsServices
dotnet add package System.Net.NameResolution
И затем замените Program.fs на:
open System
open System.Threading.Tasks
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Hosting
open Microsoft.Extensions.Logging
type Worker(logger : ILogger<Worker>) =
inherit BackgroundService()
let _logger = logger
override bs.ExecuteAsync stoppingToken =
let f : Async<unit> = async {
while not stoppingToken.IsCancellationRequested do
_logger.LogInformation("Worker running at: {time}", DateTime.Now)
do! Async.Sleep(1000)
}
Async.StartAsTask f :> Task
let CreateHostBuilder argv : IHostBuilder =
let builder = Host.CreateDefaultBuilder(argv)
builder.UseWindowsService()
.ConfigureServices(fun hostContext services -> services.AddHostedService<Worker>()
|> ignore<IServiceCollection>)
[<EntryPoint>]
let main argv =
let hostBuilder = CreateHostBuilder argv
hostBuilder.Build().Run()
0 // return an integer exit code
И, наконец, если вы находитесь на windows до Создайте реестр и запустите службу:
dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true /p:Trimmed=true -o "./published"
sc create FsharpService binPath= "%cd%\published\FsharpService.exe"
services.msc
Подробнее об этом можно узнать в моем блоге .
Другая технология, на которую я бы посмотрел, была бы Задача параллельной библиотеки . Это позволяет вам создать рабочий процесс, некоторые или все из которых могут быть параллельными, но с параллелизмом и передачей сообщений между блоками. Это просто для вызова из F # и модели, где каждый блок имеет тип ввода и (в некоторых случаях) тип вывода поддается F # проектированию с типами подход.
Вот Простой пример я собрал, когда впервые посмотрел на TPL и F #. NB: у меня не было возможности запустить это и подтвердить, что он все еще работает, также вам нужно будет изменить команду #r для работы на вашем компьютере, если вы попытаетесь использовать ее.
#r @"System.Threading.Tasks.Dataflow.dll"
open System
open System.IO
open System.Threading.Tasks.Dataflow
let buildPropagateLinkOption () =
let mutable linkOption = new DataflowLinkOptions()
linkOption.PropagateCompletion <- true
linkOption
let buildParallelExecutionOption noThreads =
let mutable executionOption = new ExecutionDataflowBlockOptions()
executionOption.MaxDegreeOfParallelism <- noThreads
executionOption
type TPLRequest = {
path:string ;
filter:string ;
}
type TPLFile = {
fileName : string ;
}
type TPLResponse = {
fileName : string ;
size : int64 ;
}
let b1Impl (inReq:TPLRequest) : TPLFile seq =
printfn "Directory %s %A" inReq.path System.Threading.Thread.CurrentThread.ManagedThreadId
Directory.EnumerateFiles(inReq.path, inReq.filter) |> Seq.map(fun x -> {fileName = x})
let b2Impl (inReq:TPLFile) : TPLResponse =
let fInfo = FileInfo(inReq.fileName)
printfn "File %s %A" inReq.fileName System.Threading.Thread.CurrentThread.ManagedThreadId
{fileName = inReq.fileName; size = fInfo.Length }
let b3Impl (inReq:TPLResponse) =
printfn "%s %d %A" inReq.fileName inReq.size System.Threading.Thread.CurrentThread.ManagedThreadId
let buildFlow () =
let parallelExecutionOption = buildParallelExecutionOption 4
let b1 = new TransformManyBlock<TPLRequest,TPLFile>((fun x -> b1Impl x),parallelExecutionOption)
let b2 = new TransformBlock<TPLFile,TPLResponse>((fun x -> b2Impl x),parallelExecutionOption)
let b3 = new ActionBlock<TPLResponse>((fun x ->b3Impl x),parallelExecutionOption)
let propagateLinkOption = buildPropagateLinkOption ()
b1.LinkTo(b2,propagateLinkOption) |> ignore<IDisposable>
b2.LinkTo(b3,propagateLinkOption) |> ignore<IDisposable>
b1
let runFlow () =
let flow = buildFlow ()
flow.Post {path="C:\\temp"; filter = "*.txt"} |> ignore<bool>
flow.Post {path="C:\\temp"; filter = "*.zip"} |> ignore<bool>
flow.Complete()
flow.Completion.Wait()
()
runFlow ()