Fluxos de trabalho assíncronos (F#)
Este tópico descreve o suporte no F# para executar cálculos assincronamente, ou seja, sem bloquear a execução de outro trabalho. Por exemplo, as computações assíncronas podem ser usadas para escrever aplicativos que possuem interfaces de usuário permaneçam responsivos a usuários conforme o aplicativo execute outro trabalho.
async { expression }
Comentários
Na sintaxe anterior, a computação é representado por expression está configurado para execução assíncrona, ou seja, sem bloquear o segmento de computação atual, quando as operações assíncronas de suspensão, e/S e outras operações assíncronas são executadas. Computações assíncronas geralmente são iniciadas em um thread de segundo plano, enquanto a execução continua no segmento atual. O tipo da expressão é Async<'a>, onde 'a é o tipo retornado pela expressão quando o return palavra-chave é usada. O código em uma expressão como essa é conhecido como um assíncrono bloco, ou async bloco.
Existem várias maneiras de programação de forma assíncrona e o Async classe fornece métodos que oferecem suporte a vários cenários. A abordagem geral é criar Async objetos que representam a computação ou computações serem executados de forma assíncrona e inicie essas computações usando uma das funções de disparo. As várias funções de disparo fornecem diferentes maneiras de executar as computações assíncronas e que você usar depende se você deseja usar o thread atual, um segmento de plano de fundo, ou um.Objeto de tarefa do NET Framework, e se existem funções de continuação que devem ser executado quando a computação é concluída. Por exemplo, para iniciar uma computação assíncrona no thread atual, você pode usar Async.StartImmediate. Quando você inicia uma computação assíncrona do thread da interface do usuário, você não bloqueie o loop principal do evento que processa as ações do usuário como, por exemplo, pressionamentos de tecla e a atividade do mouse, para que seu aplicativo permaneça responsivo.
Vinculação assíncrona usando let!
Em um fluxo de trabalho assíncrono, algumas operações e as expressões são síncronas e alguns são mais cálculos que são projetados para retornar um resultado de forma assíncrona. Quando você chama um método de forma assíncrona, em vez de um comum let de vinculação, use let!. O efeito de let! é permitir a execução continue em outros cálculos ou segmentos, como a computação está sendo executada. Após o lado direito da let! retorna de ligação, o restante do fluxo de trabalho assíncrono continua a execução.
O código a seguir mostra a diferença entre let e let!. A linha de código que usa let apenas cria uma computação assíncrona como um objeto que pode ser executada mais tarde usando, por exemplo, Async.StartImmediate ou Async.RunSynchronously. A linha de código que usa let! inicia a computação e, em seguida, o thread está suspenso até que o resultado esteja disponível, no qual ponto a execução continua.
// let just stores the result as an asynchronous operation.
let (result1 : Async<byte[]>) = stream.AsyncRead(bufferSize)
// let! completes the asynchronous operation and returns the data.
let! (result2 : byte[]) = stream.AsyncRead(bufferSize)
Além das let!, você pode usar use! para realizar as vinculações assíncronas. A diferença entre let! e use! é o mesmo que a diferença entre let e use. Para use!, o objeto é descartado no fechamento do escopo atual. Observe que na versão atual do idioma F#, use! não aceita um valor a ser inicializadas como null, mesmo que use oferece.
Primitivos assíncronos
Um método que executa uma única tarefa assíncrona e retorna o resultado é chamado um primitivo assíncrono, e elas foram desenvolvidas especificamente para uso com o let!. Vários primitivos assíncronos são definidos na biblioteca do núcleo F#. Dois desses métodos para aplicativos da Web são definidos no módulo Microsoft.FSharp.Control.WebExtensions: WebRequest.AsyncGetResponse e WebClient.AsyncDownloadString. Ambos os primitivos de baixar dados a partir de uma página da Web, fornecida uma URL. AsyncGetResponseproduz uma WebResponse o objeto, e AsyncDownloadString produz uma seqüência de caracteres que representa o HTML para uma página da Web.
Vários primitivos para operações de e/S assíncronas são incluídos no . Control. CommonExtensions module. Esses métodos de extensão da Stream classe são Stream.AsyncRead e Stream.AsyncWrite.
Primitivos assíncronos adicionais estão disponíveis em PowerPack o F#. Você também pode escrever seus próprios primitivos assíncronos, definindo uma função cujo corpo total está contido em um bloco de async.
Para usar os métodos assíncronos na.NET Framework que se destinam a outros modelos assíncronos com o F# modelo de programação assíncrona, que você cria uma função que retorna um F# Async objeto. A biblioteca do F# possui funções que tornam isso fácil de fazer.
Um exemplo de uso de fluxos de trabalho assíncronos está incluído aqui. Existem muitos outros na documentação para os métodos da classe Async.
Exemplo
Este exemplo mostra como usar fluxos de trabalho assíncronos para realizar cálculos em paralelo.
No seguinte exemplo de código, uma função fetchAsync obtém o texto HTML retornado de uma solicitação da Web. O fetchAsync função contém um bloco assíncrono de código. Quando uma ligação é feita com o resultado de um primitivo assíncrono, neste caso AsyncDownloadString, let! é usado em vez de let.
Você usa a função Async.RunSynchronously para executar uma operação assíncrona e esperar que seu resultado. Por exemplo, você poderá executar várias operações assíncronas em paralelo usando o Async funcionam em conjunto com o Async.RunSynchronously função. O Async.Parallel função leva a uma lista da Async objetos, configura o código para cada Async objeto de tarefa a ser executado em paralelo e retorna um Async objeto que representa a computação paralela. Assim como para uma única operação, você chamar Async.RunSynchronously para iniciar a execução.
O runAll função inicia três fluxos de trabalho assíncronos em paralelo e aguarda até que todas elas são concluídas.
open System.Net
open Microsoft.FSharp.Control.WebExtensions
let urlList = [ "Microsoft.com", "https://www.microsoft.com/"
"MSDN", "https://msdn.microsoft.com/"
"Bing", "https://www.bing.com"
]
let fetchAsync(name, url:string) =
async {
try
let uri = new System.Uri(url)
let webClient = new WebClient()
let! html = webClient.AsyncDownloadString(uri)
printfn "Read %d characters for %s" html.Length name
with
| ex -> printfn "%s" (ex.Message);
}
let runAll() =
urlList
|> Seq.map fetchAsync
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
runAll()