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

标签 asynchronous f# functional-programming

您可以使用哪些不同的技术在 F# 中创建 Async<'T> 的实例?

我看到有许多用于 Web 客户端/请求和文件流的扩展方法,但是如果我想编写自己的异步计算提供程序,我将如何编写这些 AsyncDoSomething我的同步版本 DoSomething职能?

我知道你可以使用相同签名的委托(delegate)来包装原始函数,然后使用Async.FromBeginEndBeginInvokeEndInvoke方法:

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

但这感觉有点勉强,而且它似乎不是“F# 方式”,因为您必须使用在 C# 或 VB 中定义的委托(delegate)(其中当然有很多 System.ActionSystem.Func 变体可供选择) 因为 F# 代表不支持 BeginInvokeEndInvoke方法。

有没有人列出可以在 F# 中编写同步函数的异步版本的不同方法?

提前谢谢了!

最佳答案

来自 docs for Async , 所有 AwaitXXXFromXXX方法。但最常见的方式是使用 asynchronous workflows .然而,正如 Mauricio 评论的那样,用 async { } 包装任意代码并不总是有益的。

更新

这里有一些代码来证明这一点。

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

包装同步Stream.Readasync { }没有明显的好处。异步工作流主要是链接异步操作的便捷方式。也就是说,它依赖于编写良好的异步操作作为构建 block 。

关于asynchronous - 如何在 F# 中创建同步函数的异步版本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8605107/

相关文章:

javascript - RxJS filter() 意外行为

Python - 多进程池中的 make_archive zip 无法正常工作

f# - 在 F# 中获取目录大小的惯用方法

dictionary - 高效的 Redux reducers,避免不必要的对象复制

scala - 用函数代码替换 if-else

正则表达式正在抓取前面的字符

c# - 不等待 lambda foreach 中的异步调用

c# - 使用 TaskCompletionSource 作为 WaitHandle 的替代品是否可以接受?

c# - 无法将任务<List<TEntity>> 转换为任务<IList<TEntity>>

f# - 为什么我的代码不能编译?