F#异步处理

时间:2011-09-15 15:29:56

标签: asynchronous f#

我写了这个小小的网络监听模拟:

Agent.Start(fun (_ : MailboxProcessor<unit>) ->
        let listener = new HttpListener()
        listener.Prefixes.Add(addr)
        listener.Start()

        let rec respondOut() = async {
                let! context = Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
                use s = context.Response.OutputStream
                let wr = new StreamWriter(s)
                use disp = { new IDisposable with
                                member x.Dispose() =
                                    printfn "Disposing..."
                                    wr.Dispose() }
                wr.Write("Test")
                return! respondOut()
            }

        respondOut()
    )

我不明白为什么每次循环都没有调用Dispose?

作为一个附带问题,我正在做这一切,因为我想测试在Web服务中响应文本的正确行为。我不确定我是否应该这样做:

use s = Context.Response.OutputStream
use sw = new StreamWriter(s)
    sw.Write("test")

Context.Response.Write("Test")
Context.Response.End()

或诸如此类的。

谢谢!

3 个答案:

答案 0 :(得分:5)

如有疑问,请使用反射器:)。 use关键字创建“使用”的范围,直到块的结尾。在异步工作流程中使用时,如果您对async关键字进行除糖,则会得到类似的内容:

Async.Bind(Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
           (fun context ->
                use s = context.Response.OutputStream
                let wr = new StreamWriter(s)
                use disp = { new IDisposable with
                                member x.Dispose() =
                                    printfn "Disposing..."
                                    wr.Dispose() }
                wr.Write("Test")
                Async.ReturnFrom ( respondOut() )
                )

现在调用Async.ReturnFrom最后将继续以递归方式调用该函数,如果用“C#using(){}”替换使用,其中}括号位于Async.ReturnFrom之后,那么dispose永远不会被调用< / p>

将使用部分包装在do块中可以解决问题:

let rec respondOut() = async {
                let! context = Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
                do 
                    use s = context.Response.OutputStream
                    let wr = new StreamWriter(s)
                    use disp = { new IDisposable with
                                    member x.Dispose() =
                                        printfn "Disposing..."
                                        wr.Dispose() }
                    wr.Write("Test")
                return! respondOut()
            }

答案 1 :(得分:2)

use延伸到块的末尾,所以我希望在递归计算返回之后将Dispose称为(在这种情况下,从不它无条件地循环)。如果您想先处理资源,则需要以某种方式界定use绑定的范围。也许这样的事情会起作用(我没试过):

let rec respondOut() = async {
    let! context = Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
    do! async {
        use s = context.Response.OutputStream
        let wr = new StreamWriter(s)
        use disp = { new IDisposable with
                     member x.Dispose() =
                         printfn "Disposing..."
                         wr.Dispose() }
        wr.Write("Test")
    }
    return! respondOut()
}

答案 2 :(得分:0)

我的猜测disp已经在编译后的代码中进行了优化,因为它没有被使用。尝试在下一行添加printfn "%A" disp