导管:如何?具有背压的多个生产者到一个消费者

时间:2019-03-27 20:34:42

标签: haskell conduit

无论如何,我是否可以表达“背压”来抑制来自导管源的值的产生?

假设我有类似的东西:

source :: ConduitT () Tweet Twitter ()
source = do
  ts <- lift $ getNewTweets [("screen_name", "Bits90824664")]
  yieldMany ts
  _ <- liftIO $ threadDelay 3000000
  source

getNewTweets通过受限制的Web API请求其数据的位置。通过在生产者中添加threadDelay,我已经能够成功地“调整”正在执行的请求数量。但是,我计划在管道中添加其他源,并开始以循环方式使用每个生产者的数据。因此,在生产者中放置threadDelay不再有意义。我想把延迟放在上游。

我已经尝试了诸如增加消费者延迟或将iterMCthreadDelay添加到管道中间的事情,但是什么也没做。我猜测正在发生多线程,因此延迟无法正常工作?

或者,一个新想法!在大多数情况下,我的生产者根本不产生任何值,而是执行yieldMany [] ...,因此,除非我将[]视为正常的流值并且将生产者重写为ConduitT () [Value] IO ()关于这是否可以与消费者的大块(CE)变体一起使用的任何想法,还是可以将空块以某种方式短路?我在想使用非块状变压器添加延迟,以便每次请求都会触发该延迟,并在管道末端使用使用者的CE变体之一。如果有机会,我会做实验。

如果在Haskell中还有其他技术可以对这种行为进行编码,那么我将感谢任何建议,因为我对Haskell相对较新,尤其是导管库。我什至不知道如何/是否可以循环浏览多个来源。

1 个答案:

答案 0 :(得分:0)

更改流以返回数据块(包括空块)可以将延迟添加到上游。我有一个与ZipSource一起使用的粗略原型,但很可能需要更改我的方法,以使源彼此独立地提取数据。

followUser :: Text -> ConduitT () [Tweet] Twitter ()
followUser sn = do
  ts <- lift $ getNewTweets [("screen_name", sn)]
  yield ts
  source

handleTweet :: Tweet -> IO ()
handleTweet = print

main :: IO ()
main = do
  let sources = sequenceSources [ followUser "user1"
                                , followUser "user2"
                                ]

  _ <- runTwitter $ runConduit
    $ sources
    .| iterMC (\a -> threadDelay 3000000)
    .| mapM_CE (liftIO . Prelude.mapM_ handleTweet)

  return ()