使用F#的内置异步支持和* Async()方法

时间:2009-10-12 16:10:38

标签: f# asynchronous webclient

如何使用F#内置支持异常操作类公开Event-based Asynchronous Pattern,例如 WebClient 类?

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

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

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

我收到错误消息:

  

类型约束不匹配。类型单元与Async<'a>类型不兼容。类型“单位”与“Async<”a>'

类型不兼容

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

1 个答案:

答案 0 :(得分:5)

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*开头。


[编辑添加以回复评论:]

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

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

为了它的价值,如果您安装了F#,您还应该拥有源代码,它将让您了解F#团队如何实现其异步扩展。在我的机器上,相关文件位于:

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