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 active
SqlCommand
s(当然,直到我结束为止),而不是在前一批大小N完成后启动连续的大小N批

问题:

  • 我是在重新发明轮子吗?换句话说,是否有库函数已经做到了这一点?(以某种方式研究开发是否有利可图?)

  • 如果不是,我应该如何实现连续队列而不是一系列离散批次


我主要不是寻求改进现有代码的建议,但这些建议仍将受到关注和感谢。

。我不确定这是否是最好的实现。但它的易用性非常好,而且由于我的应用程序不需要最高性能,所以对我来说,它工作得足够好。尽管它是一个库,但如果有人知道如何使它更好,那么让库在开箱即用的情况下表现最好总是一件好事,这样我们其他人就可以使用有效的代码,完成我们的工作

这看起来很适合反应流。你看到了吗@不,谢谢你提醒我这些。我的搜索没有找到它们。@FyodorSoikin你能详细说明一下吗?我正在从数据库中提取信息;我对反应流的体验是在推送消息的背景下进行的。我想我可以使用F#agents:)写一个答案,感谢@ildjarn指出我已经做了两次了!
let names =
    asyncWorkflows
    |> batch 20
    |> Async.RunSynchronously