我写了一个计算语料库中NGrams频率的程序。我已经拥有一个消耗代币流并生成单个订单NGrams的函数:
ngram :: Monad m => Int -> Conduit t m [t]
trigrams = ngram 3
countFreq :: (Ord t, Monad m) => Consumer [t] m (Map [t] Int)
目前我只能将一个流消费者连接到流源:
tokens --- trigrams --- countFreq
如何将多个流使用者连接到同一个流源? 我想有这样的事情:
.--- unigrams --- countFreq
|--- bigrams --- countFreq
tokens ----|--- trigrams --- countFreq
'--- ... --- countFreq
加号是并行运行每个消费者
修改 感谢Petr,我提出了这个解决方案
spawnMultiple orders = do
chan <- atomically newBroadcastTMChan
results <- forM orders $ \_ -> newEmptyMVar
threads <- forM (zip results orders) $
forkIO . uncurry (sink chan)
forkIO . runResourceT $ sourceFile "test.txt"
$$ javascriptTokenizer
=$ sinkTMChan chan
forM results readMVar
where
sink chan result n = do
chan' <- atomically $ dupTMChan chan
freqs <- runResourceT $ sourceTMChan chan'
$$ ngram n
=$ frequencies
putMVar result freqs
答案 0 :(得分:5)
我假设您希望所有接收器都能接收所有值。
我建议:
newBroadcastTMChan
创建新频道Control.Concurrent.STM.TMChan
(stm-chans)。Data.Conduit.TMChan
(stm-conduit)的sinkTBMChan
为您的主要制作人构建接收器。dupTMChan
创建自己的副本以供阅读。使用sourceTBMChan
(我没试过,请告诉我们它的工作原理。)
更新:收集结果的一种方法是为每个消费者线程创建一个MVar
。它们中的每一个都会在结束后putMVar
结果。并且你的主线程将takeMVar
放在所有这些MVar
上,从而等待每个线程完成。例如,如果vars
是您MVar
的列表,则主线程会发出mapM takeMVar vars
来收集所有结果。