Haskell中的并发HTTP请求

Haskell中的并发HTTP请求,haskell,asynchronous,concurrency,Haskell,Asynchronous,Concurrency,我有一组函数,用于从AsanaAPI构建子任务树。为此,我有一个相当简单的模块“Asana.hs”,它最重要的两个功能是使用Network.HTTP.simple执行请求: getTasksForProject::String->String->IO[Task] getTasksForProject令牌projectId=getFromAsana令牌$“projects/”++projectId++“/tasks” getSubtasks::String->String->IO[任务] getS

我有一组函数,用于从AsanaAPI构建子任务树。为此,我有一个相当简单的模块“Asana.hs”,它最重要的两个功能是使用
Network.HTTP.simple
执行请求:

getTasksForProject::String->String->IO[Task]
getTasksForProject令牌projectId=getFromAsana令牌$“projects/”++projectId++“/tasks”
getSubtasks::String->String->IO[任务]
getSubtasks token taskId=getFromAsana token$“任务/”+++taskId++“/subtasks”
问题是,当我想构建一个包含所有任务的图表时,我必须:

  • 获取任务列表
  • 迭代这些任务以获取其子任务
  • 重现
  • 例如,我使用以下函数来构造节点和边的“图”:

    type TaskGraph=([Task],[Edge])
    合并::TaskGraph->TaskGraph->TaskGraph
    合并(aTasks,aEdges)(任务,bEdges)=(aTasks++bTasks,aEdges++bEdges)
    makeEdge::关系->任务->任务->边缘
    makeEdge rel父级子级=Edge rel(taskId父级)(taskId子级)
    rFetchTaskGraph::String->Task->IO TaskGraph
    rFetchTaskGraph令牌任务=do
    子任务而不是

    mapM (rFetchTaskGraph token) subtasks
    
    使用

    图书馆在哪里

    但是,在进行并发HTTP请求时,应该小心地限制它们,以免使远程服务器崩溃或被其禁止。进行节流的一种简单方法是,使用a对
    rFetchTaskGraph
    的所有调用进行选通,如中所述

    因为
    rFetchTaskGraph
    是递归的,所以它应该接受信号量作为参数,以便将其传递给其子调用:

    rFetchTaskGraph :: QSem -> String -> Task -> IO TaskGraph
    rFetchTaskGraph sem token task = 
        bracket_ 
          (waitQSem sem) 
          (signalQSem sem)
          (do
            subtasks <- getSubtasks token $ taskId task
            let edges = map (makeEdge Subtask task) subtasks
            foldr merge ([task], edges) <$> mapConcurrently (rFetchTaskGraph sem token) subtasks)
    
    rFetchTaskGraph::QSem->String->Task->IO TaskGraph
    rFetchTaskGraph sem令牌任务=
    括号
    (waitQSem)
    (信号QSEM sem)
    (做
    
    子任务听起来像是一个很好的用例,但我自己还没有使用过。感谢您的全面回答,我将研究所有这些选项,因为节流对我来说是一个重要的后续问题。出于兴趣,为什么您会发出信号说,
    QSem
    的单元在等待后立即可用?这难道不会释放资源吗当它还在“使用中”,也就是说,如果
    do
    块需要很长的时间,那么大量操作同时运行也会遇到同样的问题?没关系,我不知道
    方括号
    做了什么,但在hoogle上查找了它:@GTF我想我的限制代码可能有问题。它同时包装了
    getsubtask
    调用和递归ive步骤。但这可能会导致死锁。也许你应该将
    括号
    的范围仅限于
    getSubtasks token$taskId task
    部分。我所做的是分析代码,我大部分时间都能看到这一点(我想)花费在
    getFromAsana
    中,这是HTTP请求和反序列化(通过Aeson)发生的地方。
    merge
    中的累积时间几乎为零。
    rFetchTaskGraph :: QSem -> String -> Task -> IO TaskGraph
    rFetchTaskGraph sem token task = 
        bracket_ 
          (waitQSem sem) 
          (signalQSem sem)
          (do
            subtasks <- getSubtasks token $ taskId task
            let edges = map (makeEdge Subtask task) subtasks
            foldr merge ([task], edges) <$> mapConcurrently (rFetchTaskGraph sem token) subtasks)
    
    rFetchTaskGraph sem token task = do
           subtasks <- bracket_ (waitQSem sem) (signalQSem sem) $ getSubtasks token $ taskId task
           let edges = map (makeEdge Subtask task) subtasks
           foldr merge ([task], edges) <$> mapConcurrently (rFetchTaskGraph sem token) subtasks