简体   繁体   English

如何在F#中创建同步函数的异步版本?

[英]How to create async version of a synchronous function in F#?

What are the different techniques you can use to create instances of Async<'T> in F#? 您可以使用哪些不同的技术在F#中创建Async <'T>的实例?

I see there are a number of extension methods for web client/request and file stream, but if I want to write my own provider of async computations, how would I go about writing those AsyncDoSomething versions of my synchronous DoSomething functions? 我看到Web客户端/请求和文件流有很多扩展方法,但如果我想编写自己的异步计算提供程序,我将如何编写同步DoSomething函数的AsyncDoSomething版本?

I know that you can use a delegate of the same signature to wrap the original function, and then use Async.FromBeginEnd on the BeginInvoke and EndInvoke methods: 我知道您可以使用相同签名的委托来包装原始函数,然后在BeginInvokeEndInvoke方法上使用Async.FromBeginEnd

open System

let del : Func<int> = new Func<int>(fun () -> 42)
let delAsync = async {
    let! res = Async.FromBeginEnd(del.BeginInvoke, del.EndInvoke)
    printfn "result was %d" res
}

Async.Start delAsync

But this feels a little forced and it doesn't seem to be the 'F# way' as you have to use delegates defined in C# or VB (of which there are plenty of System.Action and System.Func variants to choose from of course) because F# delegates don't support the BeginInvoke and EndInvoke methods. 但这感觉有点强迫,它似乎不是'F#方式'因为您必须使用在C#或VB中定义的委托(其中有很多System.ActionSystem.Func变体可供选择) )因为F#委托不支持BeginInvokeEndInvoke方法。

Does anyone have a list of the different ways you can write an async version of a synchronous function in F#? 有没有人有一个列表,你可以在F#中编写同步函数的异步版本的不同方法?

Many thanks in advance! 提前谢谢了!

From the docs for Async , all the AwaitXXX and FromXXX methods. Async文档 ,所有AwaitXXXFromXXX方法。 But the most common way is using asynchronous workflows . 但最常见的方法是使用异步工作流程 However, as Mauricio commented, wrapping arbitrary code with async { } isn't always beneficial. 但是,正如Mauricio评论的那样,用async { }包装任意代码并不总是有益的。

UPDATE UPDATE

Here's a bit of code to demonstrate that point. 这里有一些代码来证明这一点。

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

Wrapping the synchronous Stream.Read with async { } yields no observable benefits. 使用async { }包装同步Stream.Read不会产生任何可观察到的好处。 An async workflow is primarily a convenient way to chain asynchronous operations. 异步工作流主要是链接异步操作的便捷方式。 That is, it depends on having well-written asynchronous operations to start with, to serve as building blocks. 也就是说,它取决于具有良好编写的异步操作,以作为构建块。

And you can write like this: 你可以像这样写:

let doAsyncTask  (f : unit->'a) = 
     async { return! Task<'a>.Factory.StartNew( new Func<'a>(f) ) |> Async.AwaitTask }

and use it like 并使用它

let asyncFunc arg = async { return! doAsyncTask( fun () -> syncFunc arg ) } 

You could get some good mileage from Async.FromContinuations. 你可以从Async.FromContinuations获得一些好的里程。 That function allows you to define an Async from continuation functions. 该函数允许您从延续函数定义Async。 If you look at the definition of WebClient's AsyncDownloadString, you'll see this in use. 如果你看一下WebClient的AsyncDownloadString的定义,你会看到它正在使用中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM