Melhores práticas para paralelizar usando o fluxo de trabalho assíncrono
-
20-08-2019 - |
Pergunta
Vamos dizer que eu queria raspar uma página web, e extrair alguns dados. Eu ia escrever algo mais provável como esta:
let getAllHyperlinks(url:string) =
async { let req = WebRequest.Create(url)
let! rsp = req.GetResponseAsync()
use stream = rsp.GetResponseStream() // depends on rsp
use reader = new System.IO.StreamReader(stream) // depends on stream
let! data = reader.AsyncReadToEnd() // depends on reader
return extractAllUrls(data) } // depends on data
O let!
diz F # para executar o código em outro segmento, em seguida, ligam o resultado a uma variável, e continuar o processamento. O exemplo acima usa duas declarações let: um para obter a resposta, e um para ler todos os dados, de modo que ele gera pelo menos dois tópicos (por favor me corrijam se eu estiver errado)
Embora o fluxo de trabalho acima gera vários threads, a ordem de execução é de série, porque cada item no fluxo de trabalho depende do item anterior. Não é realmente possível avaliar todos os itens ainda mais para baixo o fluxo de trabalho até que os outros tópicos retornar.
Há algum benefício para ter mais de um let!
no código acima?
Se não, como é que esta necessidade código para alterar para tirar proveito de várias instruções let!
?
Solução
A chave é que são não desova quaisquer novos tópicos. Durante todo o curso do fluxo de trabalho, há 1 ou 0 tópicos ativos que estão sendo consumidos a partir do ThreadPool. (Uma exceção, até o primeiro '!', O código é executado no segmento do usuário que fez um Async.Run.) "Vamos!" deixa para ir de um segmento enquanto a operação assíncrona está no mar, e depois pega um thread do ThreadPool quando a operação retorna. O (desempenho) vantagem é menos pressão contra o ThreadPool. (E, claro, a grande vantagem de usuário é o modelo de programação simples - um milhão de vezes melhor do que tudo o que BeginFoo / EndFoo / callback coisas que de outra forma escrita)
Veja também http://cs.hubfs.net/forums/thread/8262. aspx
Outras dicas
Eu estava escrevendo uma resposta, mas Brian chegou antes de mim. Concordo plenamente com ele.
Eu gostaria de acrescentar que, se você quiser paralelizar código síncrono, a ferramenta certa é PLINQ, não assíncrona fluxos de trabalho, como Don Syme explica .