Asynchronous 如何限制传递给async.Parallel的大量异步工作流
我有一个数组,其中包含大量小型异步数据库查询;例如:Asynchronous 如何限制传递给async.Parallel的大量异步工作流,asynchronous,f#,Asynchronous,F#,我有一个数组,其中包含大量小型异步数据库查询;例如: // I actually have a more complex function that // accepts name/value pairs for query parameters. let runSql connString sql = async { use connection = new SqlConnection(connString) use command = new SqlCommand(sql,
// I actually have a more complex function that
// accepts name/value pairs for query parameters.
let runSql connString sql = async {
use connection = new SqlConnection(connString)
use command = new SqlCommand(sql, connection)
do! connection.OpenAsync() |> Async.AwaitIAsyncResult |> Async.Ignore
return! command.ExecuteScalarAsync() |> Async.AwaitTask
}
let getName (id:Guid) = async {
// I actually use a parameterized query
let querySql = "SELECT Name FROM Entities WHERE ID = '" + id.ToString() + "'"
return! runSql connectionString querySql
}
let ids : Guid array = getSixtyThousandIds()
let asyncWorkflows = ids |> Array.map getName
//...
现在,问题是:下一个表达式一次运行所有60K工作流,淹没服务器。这导致许多SqlCommand
s超时;它通常还会导致客户端内存不足异常(这是F#interactive),原因我不理解,也没有调查(不需要理解):
//...
let names =
asyncWorkflows
|> Async.Parallel
|> Async.RunSynchronously
我已经编写了一个粗略的函数来批处理请求:
let batch batchSize asyncs = async {
let batches = asyncs
|> Seq.mapi (fun i a -> i, a)
|> Seq.groupBy (fst >> fun n -> n / batchSize)
|> Seq.map (snd >> Seq.map snd)
|> Seq.map Async.Parallel
let results = ref []
for batch in batches do
let! result = batch
results := (result :: !results)
return (!results |> List.rev |> Seq.collect id |> Array.ofSeq)
}
要使用此函数,我将Async.Parallel
替换为batch 20
(或另一个整数值):
这工作得相当好,但我更希望有一个系统在完成每个新异步后立即启动,因此,我总是等待N activeSqlCommand
s(当然,直到我结束为止),而不是在前一批大小N完成后启动连续的大小N批
问题:
- 我是在重新发明轮子吗?换句话说,是否有库函数已经做到了这一点?(以某种方式研究开发是否有利可图?)
- 如果不是,我应该如何实现连续队列而不是一系列离散批次
我主要不是寻求改进现有代码的建议,但这些建议仍将受到关注和感谢。。我不确定这是否是最好的实现。但它的易用性非常好,而且由于我的应用程序不需要最高性能,所以对我来说,它工作得足够好。尽管它是一个库,但如果有人知道如何使它更好,那么让库在开箱即用的情况下表现最好总是一件好事,这样我们其他人就可以使用有效的代码,完成我们的工作 这看起来很适合反应流。你看到了吗@不,谢谢你提醒我这些。我的搜索没有找到它们。@FyodorSoikin你能详细说明一下吗?我正在从数据库中提取信息;我对反应流的体验是在推送消息的背景下进行的。我想我可以使用F#agents:)写一个答案,感谢@ildjarn指出我已经做了两次了!
let names =
asyncWorkflows
|> batch 20
|> Async.RunSynchronously