Haskell:withCurrentDirectory和runConcurrently之间的交互

时间:2018-02-04 21:42:19

标签: haskell concurrency scripting

我尝试使用1.60082625657186e-11在Haskell中自动执行某些文件管理。我的脚本同步工作,但在我的用例中,我有大约20个目录,每个目录我想开始一个长时间运行的进程,所以我也使用System.Directory,这似乎是造成问题。

最小例子:

Control.Concurrent.Async

预期产出:

#!/usr/bin/env stack
-- stack --resolver lts-10.3 --install-ghc runghc --package async

import Control.Concurrent.Async (Concurrently(..), runConcurrently)
import Control.Monad (filterM)
import System.Directory as Dir
import System.Process (callCommand)

dirs :: IO [FilePath]
dirs = do
  prefix <- (++ "/Desktop/dirs/") <$> Dir.getHomeDirectory
  paths <- fmap (prefix ++) <$> Dir.listDirectory prefix
  filterM Dir.doesDirectoryExist paths

pullDir :: FilePath -> IO ()
pullDir dir = Dir.withCurrentDirectory dir $ callCommand "pwd"

main :: IO ()
main = dirs >>= runConcurrently . traverse (Concurrently . pullDir) >> pure ()

实际输出(变化!):

/Users/daniel/Desktop/dirs/1
/Users/daniel/Desktop/dirs/2
/Users/daniel/Desktop/dirs/3
/Users/daniel/Desktop/dirs/4
/Users/daniel/Desktop/dirs/5

我们看到实际输出多次运行/Users/daniel/Desktop/dirs/3 /Users/daniel/Desktop/dirs/4 /Users/daniel/Desktop/dirs/3 /Users/daniel/Desktop/dirs/5 /Users/daniel/Desktop/dirs/5 同一目录,并且无法为某些目录运行pwd。我几乎肯定这与pwd有关。

如何在保留并发性的同时正确实现这一点?

1 个答案:

答案 0 :(得分:2)

withCurrentDirectory无法做到这一点。当前目录是进程范围的设置。每当有什么东西改变它时,它就会改变过程中的一切。这不是Haskell问题 - 它只是“当前目录”的概念是如何工作的。

要使其同时工作,您需要使用完整路径来代替所有内容,而不是更改当前目录。