我有一个代理程序,我设置它在后台执行一些数据库工作。实现大致如下:
let myAgent = MailboxProcessor<AgentData>.Start(fun inbox ->
let rec loop =
async {
let! data = inbox.Receive()
use conn = new System.Data.SqlClient.SqlConnection("...")
data |> List.map (fun e -> // Some transforms)
|> List.sortBy (fun (_,_,t,_,_) -> t)
|> List.iter (fun (a,b,c,d,e) ->
try
... // Do the database work
with e -> Log.error "Yikes")
return! loop
}
loop)
通过这个发现,如果在一定时间内多次调用此函数,我会发现SqlConnection对象不断堆积而没有被处理,最终连接池中的连接会用尽(我没有准确的“几次”指标,但连续两次运行集成测试套件总是会导致连接池用尽)。
如果我将
use
更改为using
,那么一切都会得到妥善处理,我就不会遇到问题了。let myAgent = MailboxProcessor<AgentData>.Start(fun inbox ->
let rec loop =
async {
let! data = inbox.Receive()
using (new System.Data.SqlClient.SqlConnection("...")) <| fun conn ->
data |> List.map (fun e -> // Some transforms)
|> List.sortBy (fun (_,_,t,_,_) -> t)
|> List.iter (fun (a,b,c,d,e) ->
try
... // Do the database work
with e -> Log.error "Yikes")
return! loop
}
loop)
似乎AsyncBuilder的Using方法由于某些原因没有正确调用其finally函数,但不清楚原因。这是否与我编写的递归异步表达式有关,还是一些模糊的错误?这是否意味着在其他计算表达式中利用use可能会产生相同的行为?
let rec loop()
和return! loop()
,也就是一个函数而不是值吗? - Daniel