【问题标题】:Using F#'s built-in async support with *Async() methods通过 *Async() 方法使用 F# 的内置异步支持
【发布时间】:2009-10-12 16:10:37
【问题描述】:

我如何使用 F# 对暴露 Event-based Asynchronous Pattern 的异步操作类的内置支持,例如 WebClient 类?

let Download(url : Uri) =
    let client = new WebClient()
    let html = client.DownloadString(url)
    html

当我尝试将其更改为使用“让!”在 async 块中(如 Soma 最近的 post 中所述)

let Download(url : Uri) =
    async {
    let client = new WebClient()
    let! html = client.DownloadStringAsync(url)
    return html }

我收到一条错误消息:

类型约束不匹配。 unit 类型与 Async 类型不兼容 'unit' 类型与 'Async' 类型不兼容

编辑:我真的在问使用 *Async() 方法的一般问题,WebClient 只是一个简单的例子。 Microsoft says “...您应该尽可能使用基于事件的异步模式 [ 而不是 BeginFoo()/EndFoo() ] 公开异步功能...”所以我认为应该有一种简单的消费方式来自 F# 的任意 *Async() 方法。

【问题讨论】:

    标签: f# asynchronous webclient


    【解决方案1】:

    WebClient.DownloadStringAsync 方法是 .NET 框架的一部分。它会引发一个事件来表示它的进度,它的返回类型是unit,所以你不想使用它,并且将它包装在async 对象中没有任何优势。

    F# PowerPack 定义了一个扩展方法,val webclient.AsyncDownloadString : uri -> Async{string}:

    let Download(url : Uri) =
        async {
        let client = new WebClient()
        client.Encoding <- Encoding.GetEncoding("utf-8")
        let! html = client.AsyncDownloadString(url)
        return html }
    

    不幸的是,名称的选择与现有的 webclient 方法发生冲突,这可能会引起混淆,这是可以理解的。但是,我相信所有 F# 异步扩展都以 Async* 开头。


    [编辑添加以响应 cmets:]

    通常,.NET 使用 BeginFoo / EndFoo 模式进行并发。如果类型正确,您可以使用Async.BuildPrimitive beginMethod endMethod,它将为该方法返回一个异步包装器。

    有时对象不使用这种模式,比如 WebClient,你实际上必须使用Async.AwaitEvent 来等待事件被触发,或者编写你自己的循环来反复检查是否设置了布尔值。这是一个不错的article on converting events to Async objects

    不管怎样,如果您安装了 F#,您还应该拥有源代码,这将使您了解 F# 团队如何实现他们的异步扩展。在我的机器上,相关文件位于:

    C:\Program Files\FSharp-1.9.6.16\source\fsppack\FSharp.PowerPack\AsyncOperations.fs
    

    【讨论】:

      猜你喜欢
      • 2015-03-20
      • 1970-01-01
      • 1970-01-01
      • 2019-01-17
      • 2014-03-16
      • 1970-01-01
      • 2017-05-13
      • 2018-03-10
      • 2016-03-11
      相关资源
      最近更新 更多