[英]Idiomatic prefetching in a streaming library
我正在使用流媒體庫,但會接受使用管道或管道的答案。
說我有
import Streaming (Stream, Of)
import qualified Streaming.Prelude as S
streamChunks :: Int -> Stream (Of Thing) IO ()
streamChunks lastID = do
flip fix 0 $ \go thingID ->
unless (thingID > lastID) $ do
thing <- highLatencyGet thingID
S.yield thing
go (thingID+1)
為了減少等待時間,我想叉highLatencyGet
檢索下一個Thing
與處理先前平行Thing
在消費。
顯然,我可以將我的函數轉換為創建一個新的MVar
並在調用yield
等之前分配下一批。
但我想知道是否有一種慣用的(可組合的)方法來做到這一點,這樣它就可以打包在一個庫中,並且可以在任意IO Stream
上使用。 理想情況下,我們也可以配置預取值,例如:
prefetching :: Int -> Stream (Of a) IO () -> Stream (Of a) IO ()
此解決方案使用管道,但它可以很容易地適應使用流媒體 。 確切地說,它需要管道 , 管道 - 並發和異步包。
它不能以“直接”的方式工作。 它不僅僅是簡單地轉換Producer
,還需要一個消耗Producer
的“折疊功能”。 這種延續傳遞方式對於設置和拆除並發機制是必要的。
import Pipes
import Pipes.Concurrent (spawn',bounded,fromInput,toOutput,atomically)
import Control.Concurrent.Async (Concurrently(..))
import Control.Exception (finally)
prefetching :: Int -> Producer a IO () -> (Producer a IO () -> IO r) -> IO r
prefetching bufsize source foldfunc = do
(outbox,inbox,seal) <- spawn' (bounded bufsize)
let cutcord effect = effect `finally` atomically seal
runConcurrently $
Concurrently (cutcord (runEffect (source >-> toOutput outbox)))
*>
Concurrently (cutcord (foldfunc (fromInput inbox)))
原始生產者的輸出被重定向到有界隊列。 同時,我們將producer-folding函數應用於從隊列中讀取的生產者。
每當並發操作完成時,我們會小心地立即關閉通道以避免另一側懸空。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.