代码之家  ›  专栏  ›  技术社区  ›  Rafael S. Calsaverini

关于系统、进程和多线程的一些问题

  •  4
  • Rafael S. Calsaverini  · 技术社区  · 16 年前

    我在C语言中有一个小的数值模拟(我必须在C语言中进行,以便与我的顾问共享),但我想使用类似于“haskell脚本”的东西来组织模拟。程序接受一些命令行参数并输出一些我想重定向到文件的输出,所以我做了如下操作:

     import Control.Monad
     import System.Process
    

    我有一个函数来创建输出文件的名称:

    filename :: Int -> String  
    filename n = some stuff here...
    

    我要执行的命令是:

    command :: Int -> String
    command n = "./mycutesimulation " ++ show n ++ " >" ++ filename n
    

    最后,我列出了我想要完成的跑步,并与他们一起完成。 runCommand :

    commands = map command [1,2..1000]
    
    main = do
       sequence_ $ map runCommand commands
    

    问题是,在我运行这个“脚本”之后,我的计算机几乎被负载冻结。正在执行的程序在内存使用上非常简单,只需几秒钟就可以运行。这不应该发生。

    所以,我的问题是:

    1)我是否刚刚抛出了1000个要同时执行的进程????我怎样才能以一个合理的顺序执行它们——顺序地或者一次只执行几个进程。

    2)我用四核来做这个,如果能用这个来支持我,那就太好了。我能用那个编译这个吗 -threaded 标记并获取要以有组织的方式并发执行的进程?

    3 回复  |  直到 8 年前
        1
  •  3
  •   liwp    16 年前

    首先,您应该检查top或task manager,看看您是否真的在快速连续地创建了1000个流程,然后寻找基于此的解决方案。

    减缓进程创建的一个简单方法是在创建下一个进程之前等待每个进程完成。所以不是映射 runCommand 超过你 commands 您应该映射自己的函数,该函数首先调用 运行命令 然后打电话 waitForProcess 归还 ProcessHandle 也就是说,每次调用helper函数都将阻塞,直到生成的进程完成。

    上述解决方案的缺点是它只使用四个核心中的一个。因此,要利用这四个核心,您可以做的是 partition 命令 进入四个(或您想要使用的任意多个核心)列表,然后用 forkIO 对于每个将运行 map 在那次列表上。

    顺便说一句。 mapM_ f == sequence_ . map f

        2
  •  4
  •   Aidan Cully    16 年前

    你需要一个 waitForProcess =<< runCommand .

    import System.Process
    
    main = sequence $ map (\x -> runCommand x) commands
     where commands = map (\x -> "echo " ++ show x) [1, 2..1000]
    

    和你的症状相似,但是

    import System.Process
    
    main = sequence $ map (\x -> waitForProcess =<< runCommand x) commands
     where commands = map (\x -> "echo " ++ show x) [1, 2..1000]
    

    作品。

        3
  •  1
  •   C. A. McCann Ravikant Cherukuri    16 年前

    这里有一个快速和肮脏的“一次运行几个”,如果它有帮助:

    import System.Process
    
    commands = replicate 16 "sleep 2"
    
    runSome handles cmd = do
        (h:hs) <- handles
        waitForProcess h
        h' <- runCommand cmd
        return $ hs ++ [h']
    
    test n = 
        let initial = mapM runCommand $ take n commands
        in foldl runSome initial (drop n commands)
    

    这只是(mis)使用一个列表作为一个简单的队列,运行尽可能多的命令,然后等待队列前面的命令,完成后添加一个新命令。请注意,如果混合了一些长时间运行的命令,这将不会表现得很理想,但对于您来说可能已经足够了。不过,请不要认为这是一种“正确”的方法。