asynchronous - F# 使用关键字和递归函数

标签 asynchronous recursion f# idisposable tail-recursion

据我所知,use 关键字一旦超出范围就会处理绑定(bind)的 IDisposable,所以考虑这个递归函数:

let rec AsyncAcceptMessages(client : WebSocket) =
  async {
    let! message = client.AsyncReadMessage
    use reader = new StreamReader(message)
    let s = reader.ReadToEnd()
    printf "%s" <| s
    do! AsyncAcceptMessages client
  }

假设编译器没有找到使用尾递归的方法,StreamReader 会在每次递归后被释放吗?

更新

Tomas 的回复向我展示了一种在您实际期望得到返回时修复它的方法,但是如果您什么都不期望怎么办?就像这个使用 StreamWriter 的例子:

let rec AsyncAcceptMessages(client : WebSocket) =
  async {
    let! message = client.AsyncReadMessage
    if(not(isNull message)) then 
      let s = 
        use reader = new StreamReader(message)
        reader.ReadToEnd()
      use writer = new StreamWriter(client.CreateMessageWriter(WebSocketMessageType.Text), Encoding.UTF8)
      writer.Write s
      printf "%s" <| s
    do! AsyncAcceptMessages client
  }

最佳答案

如您所说,StreamReader 只会在递归调用执行返回后 被释放(即永远不会)。

还有一个问题,就是do!没有被当作尾递归调用,所以如果你想创建一个无限尾递归循环,你需要使用 return!(否则您的代码将泄漏内存)。

在这种情况下,您可以轻松地修复它,因为您没有对 StreamReader 执行任何异步操作,所以您可以只创建一个普通的本地范围:

let rec AsyncAcceptMessages(client : WebSocket) =
  async {
    let! message = client.AsyncReadMessage
    let s = 
      use reader = new StreamReader(message)
      reader.ReadToEnd()
    printf "%s" <| s
    return! AsyncAcceptMessages client
  }

如果您想调用AsyncReadToEnd,那么您可以执行如下操作:

let rec AsyncAcceptMessages(client : WebSocket) =
  async {
    let! message = client.AsyncReadMessage
    let! s =
      async { use reader = new StreamReader(message)
              return! reader.ReadToEnd() }
    printf "%s" <| s
    return! AsyncAcceptMessages client
  }

关于asynchronous - F# 使用关键字和递归函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26976175/

相关文章:

.net - 如何使一元否定和数学函数适用于继承类型?

ios - 使 requestAVAssetForVideo 同步

ios - 在 UIScrollview 中更新 subview 时滚动期间轻微卡住

c# - 在 WPF 应用程序中正确实现任务

java - 递归乘法的正确思考方式?

f# - 无法在 C# 项目中引用 'FSharpOption<>'

javascript - 在 Controller 异步调用后添加 CSS 样式的首选 AngularJS 方式是什么?

c# - 使用 Expression.Parameter 中的子属性构建 linq 表达式

python - (错误)理解生成器

F# 字符串运算符在 guid 上爆炸