11
votes

Comment créer une version asynchreuse d'une fonction synchrone dans F #?

Quelles sont les différentes techniques que vous pouvez utiliser pour créer des instances d'ASYNC <'T> en F #?

Je vois qu'il existe un certain nombre de méthodes d'extension pour Web Client / Demande et flux de fichiers, mais si je veux écrire mon propre fournisseur de calculs ASYNC, comment irai-i d'écrire ces asyncdosomething versions de mon Dosomething Synchrone Fonctions?

Je sais que vous pouvez utiliser un délégué de la même signature pour envelopper la fonction d'origine, puis utiliser async.fombeginend sur le begininvoke et endinvoke méthodes: xxx

mais cela ressent un peu forcé et il ne semble pas Soyez la «F # Way» car vous devez utiliser des délégués définis dans C # ou VB (dont il y a beaucoup de system.action et system.func variantes au choix de Cours) parce que f # délégués ne prend pas en charge le beginInvoke et endinvoke méthodes.

Est-ce que quelqu'un a une liste des différentes façons que vous puissiez écrire une asynchrone version d'une fonction synchrone dans F #?

Merci beaucoup d'avance!


2 commentaires

Faire une asynchronisation d'une synchronisation implicite n'a pas beaucoup de sens IMHO.


Vrai, c'est surtout utile lorsque vous devez faire du travail IO (ASYNC vous permet de libérer un thread autrement bloqué dans la version de synchronisation), qui sont déjà couverts par les méthodes de vulgarisation communes de F #, mais je suis juste intéressé par «Comment «Vous allez faire ça. Peut-être qu'un jour, vous rencontrerez une méthode qui effectue des travaux io mais ne vient pas avec une paire de début / de fin, par exemple.


3 Réponses :


6
votes

du docs pour async code> , tous les AWAITEXXX code> et fromxxx code> méthodes. Mais le moyen le plus courant consiste à utiliser workflows asynchrone . Cependant, comme Mauricio a commenté, l'emballage du code arbitraire avec async {} code> n'est pas toujours bénéfique.

Mise à jour h3>

Voici un peu de code pour démontrer ce point. P >

open System.IO

let BUF_SIZE = 1 <<< 16 //64KB

let readFile f (stream:Stream) =
  let buf = Array.zeroCreate BUF_SIZE
  let rec read p =
    async {
      let! n = f stream buf 
      match n with
      | 0 -> ()
      | _ -> return! read (p + n)
    }
  read 0

let fakeAsyncReadFile s = readFile (fun stream buf -> 
  async { return stream.Read(buf, 0, buf.Length) }) s

let realAsyncReadFile s = readFile (fun stream buf -> 
  stream.AsyncRead(buf, 0, buf.Length)) s

let files = [@"C:\big_file_1"; @"C:\big_file_2"]

let readWith f = 
  let streams = Seq.map File.OpenRead files
  try Seq.map f streams |> Async.Parallel |> Async.RunSynchronously |> ignore
  finally streams |> Seq.iter (fun s -> s.Close())

readWith fakeAsyncReadFile //Real: 00:00:34.190, CPU: 00:00:03.166, GC gen0: 4, gen1: 2, gen2: 1
readWith realAsyncReadFile //Real: 00:00:05.101, CPU: 00:00:16.957, GC gen0: 31, gen1: 1, gen2: 0


4 commentaires

Pouvez-vous élaborer sur l'utilisation d'ASYNC {}? Le let! La liaison nécessite une instance d'Async <'T> sur le côté droit de l'expression, et c'est la création de ces cas d'asynchronisation <' T> qui m'intéresse.


Awahitvent et AwaitTask peut être utile si vous avez une tâche ou un événement à la main, je suppose.


Alors quelque chose comme ça? Laissez Delasync2 = async {retour 42} printfn "résultat était% d" <| ASYNC.RUNSYNYNYNYNYNCYNC2


Blog de Don Syme a quelques exemples.



3
votes

Vous pouvez obtenir un bon kilométrage d'async.fromcontinuations. Cette fonction vous permet de définir une asynchronisation des fonctions de continuation. Si vous regardez la définition de l'asyncdownloadstring de WebClient, vous le verrez en utilisation.


0 commentaires

3
votes

Et vous pouvez écrire comme ceci: xxx

et l'utiliser comme xxx


0 commentaires