Tarefa biblioteca paralela vs assíncronas Workflows
-
18-09-2019 - |
Pergunta
Eu tenho algumas coisas escrito em C # que executa o código concorrente, fazendo uso intenso da biblioteca paralela de tarefas (Task e cadeias de continuação futuro).
Agora estou portar isso para F # e estou tentando descobrir os prós e contras do uso F # Async fluxos de trabalho vs. as construções no TPL. Estou inclinado para TPL, mas acho que isso poderia ser feito de qualquer maneira.
Alguém tem dicas e sabedoria sobre como escrever programas concorrentes em F # para mostrar?
Solução
O nome resume muito bem a diferença: assíncrona programação vs. paralelo programação. Mas na F # você pode misturar e combinar.
F # assíncronos Workflows
F workflows # assíncronos são úteis quando você quer ter código de executar de forma assíncrona, que está começando uma tarefa e não ficar esperando para o resultado final. O uso mais comum é operações de IO. Ter seu fio sentar lá em um loop ocioso de espera para o seu disco rígido para terminar de escrever desperdiça recursos.
Se você começou a operação de gravação assíncrona você pode suspender o fio e tê-lo acordado mais tarde por uma interrupção de hardware.
biblioteca paralela de tarefas
A biblioteca paralela de tarefas em .NET 4.0 abstrai a noção de uma tarefa - como a decodificação de um MP3, ou ler alguns resultados de um banco de dados. Nessas situações, você realmente deseja que o resultado do cálculo e, em algum ponto no tempo mais tarde estão à espera para o resultado da operação. (Ao acessar a propriedade .Result.)
Você pode facilmente misturar e combinar esses conceitos. Tais como fazer todas as suas operações de IO em um objeto TPL tarefas. Para o programador de ter resumido a necessidade de 'acordo com a' esse segmento extra, mas debaixo das cobertas você está o desperdício de recursos.
Como sábio você pode criar uma série de F workflows # assíncronos e executá-los em paralelo (Async.Parallel), mas então você precisa esperar o resultado final (Async.RunSynchronously). Isso você liberta da necessidade de iniciar explicitamente todas as tarefas, mas na verdade você está apenas realizando a computação em paralelo.
Na minha experiência, eu acho que o TPL é mais útil porque geralmente eu quero executar operações N em paralelo. No entanto, F workflows # assíncronos são ideais quando há algo que está acontecendo 'nos bastidores', como um tipo de coisa Reactive Agente ou caixa de correio. (Você enviar algo uma mensagem, ela processa e envia-lo de volta.)
Espero que ajude.
Outras dicas
Na 4.0, eu diria:
- Se a sua função é sequencial, o uso assíncrono fluxos de trabalho. Eles simplesmente ler melhor.
- Use o TPL para tudo o resto.
Também é possível misturar e combinar. Eles adicionaram suporte para executar um fluxo de trabalho como uma tarefa e criar tarefas que seguem o assíncrono Begin padrão / End usando TaskFactory.FromAsync , o equivalente TPL de Async.FromBeginEnd ou Async.BuildPrimitive
.
let func() =
let file = File.OpenRead("foo")
let buffer = Array.zeroCreate 1024
let task1 = Task.Factory.FromAsync(file.BeginRead(buffer, 0, buffer.Length, null, null), file.EndRead)
task1.Start()
let task2 = Async.StartAsTask(file.AsyncRead(1024))
printfn "%d" task2.Result.Length
É importante notar também que tanto o tempo de execução assíncrono fluxos de trabalho e do TPL está indo para criar um núcleo adicional primitivo (um evento) e uso WaitForMultipleObjects para rastrear I / O de conclusão, em vez de utilizar portas de conclusão e as chamadas de retorno. Isso é indesejável em algumas aplicações.