簡體   English   中英

並行排序IO操作

[英]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'

我的理由是第一個mapMIO [Int]類型的東西綁定到resultsresults'將並行策略應用於包含的列表, 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

完整的文件可以在這里找到(它有點長,但前幾個“euler X”函數應該足夠代表),我做並行性的主文件就是這個

策略是並行執行純計算。 如果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.

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