簡體   English   中英

管道:多流消費者

[英]Conduit: Multiple Stream Consumers

我寫了一個計算語料庫中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

我假設您希望所有接收器都能接收所有值。

我建議:

  1. 使用newBroadcastTMChan創建一個新的通道Control.Concurrent.STM.TMChan (stm-chans)。
  2. 使用此渠道建設用匯sinkTBMChanData.Conduit.TMChan (STM-管道)為您的主要生產商。
  3. 對於每個客戶端,使用dupTMChan創建自己的副本以供閱讀。 使用sourceTBMChan啟動將讀取此副本的新線程。
  4. 從線程中收集結果。
  5. 確保您的客戶端能夠在生成數據時盡快讀取數據,否則可能會導致堆溢出。

(我沒試過,讓我們知道它是如何工作的。)


更新:收集結果的一種方法是為每個使用者線程創建一個MVar 他們每個人都會在完成后將putMVar的結果putMVar其中。 和你的主線程會takeMVar所有這些MVar S,從而等待每一個線程來完成。 例如,如果vars是你的MVar的列表,主線程將發出mapM takeMVar vars來收集所有結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM