Во-первых, похоже, вы ошибочно пометили подпись exec
, которая, вероятно, должна быть:
exec :: FilePath -> IO [CV_scene]
Теперь о важной части. Я прокомментировал то, что, по вашему мнению, происходит.
pExec xs = do
-- A. Parse the file found at each location via exec.
ex <- mapM exec xs
-- B. Force the lazy parsing in parallel.
as <- ex `usingIO` parList rdeepseq
return as
Обратите внимание, что строка A не встречается в параллельном режиме, что, как вы можете подумать, нормально, поскольку она просто настроит парсинг разбора, который выполняется параллельно в B. Это справедливое предположение и умное использование лени, но результаты ставят это под сомнение для меня.
Я подозреваю, что реализация exec
вынуждает большую часть синтаксического анализа еще до того, как строка B будет даже достигнута, так что deep seq не делает много. Это очень хорошо подходит для моего эксперимента, и профилирование поддерживает это объяснение.
Без возможности протестировать ваш код я могу только сделать следующие предложения. Сначала попытайтесь отделить разбор файла от ввода-вывода и поместите разбор в стратегию параллельного выполнения. В этом случае линии A и B становятся примерно такими:
ex <- mapM readFile xs
as <- ex `usingIO` parList (rdeepseq . exec')
с exec'
частью exec
после чтения файла с диска.
exec' :: FilePath -> [CVScene]
Кроме того, вам может даже не понадобиться rdeepSeq
после этого изменения.
В качестве альтернативы вы можете выполнять IO и анализ параллельно, используя программную транзакционную память. Подходы STM обычно используются для отдельных потоков ввода-вывода, которые действуют скорее как сервисы, а не как чистые вычисления. Но если по какой-то причине вы не можете использовать подход, основанный на стратегиях, стоит попробовать.
import Control.Concurrent.STM.TChan --(from stm package)
import Control.Concurrent(forkIO)
pExec'' :: [FilePath] -> IO [[CVSene]]
pExec'' xs = do
-- A. create [(Filename,TChan [CVScene])]
tcx <- mapM (\x -> (x,) <$> newTChanIO) xs
-- B. do the reading/parsing in separate threads
mapM_ (forkIO . exec'') tcx
-- C. Collect the results
cvs <- mapM (atomically . readTChan . snd) tcx
exec'' :: [(FilePath,TChan [CVScene])] -> IO ()
exec'' (x,tch) = do
--D. The original exec function
cv <- exec x
--E. Put on the channel fifo buffer
atomically $ writeTChan tch cv
Удачи!