[英]Sequencing IO actions in parallel
我有一個返回IO動作的函數,
f :: Int -> IO Int
我想為參數的多個值並行計算這個函數。 我天真的實施如下:
import Control.Parallel.Strategies
vals = [1..10]
main = do
results <- mapM f vals
let results' = results `using` parList rseq
mapM_ print results'
我的理由是第一個mapM
將IO [Int]
類型的東西綁定到results
, results'
將並行策略應用於包含的列表, mapM_
最終通過打印它們來請求實際值 - 但是要打印的是已經並行啟動,因此程序應該並行化。
在確實使用了我所有的CPU后感到高興,我注意到當使用+RTS -N8
運行時,程序效率較低(如掛鍾時間),而不是沒有任何RTS標志。 我能想到的唯一解釋是第一個mapM
必須序列 - 即執行 - 所有IO動作已經,但這不會導致無效,但是使N8
執行與未mapM
一樣有效,因為所有的工作都是由主線程完成。 使用+RTS -N8 -s
運行程序會產生SPARKS: 36 (11 converted, 0 overflowed, 0 dud, 21 GC'd, 4 fizzled)
,這肯定不是最佳的,但不幸的是我無法理解它。
我想我已經在Haskell並行化或IO monad的內部找到了初學者的墊腳石之一。 我究竟做錯了什么?
背景信息: fn
是一個返回Project Euler問題n的解決方案的函數。 由於其中許多都有要讀取的數據,因此我將結果放入IO monad中。 它看起來如何的一個例子是
-- Problem 13: Work out the first ten digits of the sum of one-hundred 50-digit numbers.
euler 13 = fmap (first10 . sum) numbers
where
numbers = fmap (map read . explode '\n') $ readFile "problem_13"
first10 n
| n < 10^10 = n -- 10^10 is the first number with 11 digits
| otherwise = first10 $ n `div` 10
策略是並行執行純計算。 如果f
必須確實返回IO
值,那么請考慮使用async
包。 它為同時運行IO
操作提供了有用的組合器。
對於您的用例, mapConcurrently
看起來很有用:
import Control.Concurrent.Async
vals = [1..10]
main = do
results <- mapConcurrently f vals
mapM_ print results
(我沒有測試過,因為我不知道你的f
到底是什么。)
試試parallel-io
包。 它允許您將任何mapM_
更改為parallel_
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.