这个程序产生了多少个线程(geturls9.hs)

时间:2016-08-07 08:53:42

标签: multithreading haskell asynchronous

我正在阅读Parallel and Concurrent Programming in Haskell的第11章。在该书中,以下program用于同时获取URL:

main = do
  xs <- foldr conc (return []) (map getURL sites)
  print (map B.length xs)
 where
  conc ioa ioas = do
    (a,as) <- concurrently ioa ioas
    return (a:as)

假设“获取网址”作业为[g0, g1, g2]。据我了解,xs将绑定到以下结构:

g0 `conc` (g1 `conc` (g2 `conc` (return [])))

现在,我的问题是在这种情况下将创建多少个线程。我的猜测是将创建7个线程(而不是我希望用于此工作的4个线程):

 thread0: g0 `conc` (g1 `conc` (g2 `conc` (return [])))
   thread1: g0
   thread2: (g1 `conc` (g2 `conc` (return [])))
     thread3: g1
     thread4: (g2 `conc` (return []))
       thread5: g2
       thread6: return []

这种推理是否正确?

1 个答案:

答案 0 :(得分:2)

所有猜测都是错误的!实际上有六个线程产生。

让我们拿出大锤 -

import Control.Concurrent.Async
import Control.Concurrent (myThreadId)

import qualified Data.ByteString as B

-----------------------------------------------------------------------------

sites = ["http://www.google.com",
         "http://www.wikipedia.com/wiki/Spade",
         "http://www.wikipedia.com/wiki/Shovel"]

getURL _ = return B.empty

annotate :: IO a -> IO a
annotate action = do
    tid <- myThreadId
    putStrLn $ "I'm a thread and my ID is: " ++ show tid
    action

-- <<main
main = do
  xs <- foldr conc (return []) (map getURL sites)
  print (map B.length xs)
 where
  conc ioa ioas = do
    (a,as) <- concurrently (annotate ioa) (annotate ioas)
    return (a:as)
-- >>

传递给concurrently的所有操作都将包含annotate,这会导致线程将其ThreadId barf为stdout。运行这个我得到 -

+$ ./geturls9
I'm a thread and my ID is: ThreadId 5
I'm a thread and my ID is: ThreadId 6
I'm a thread and my ID is: ThreadId 8
I'm a thread and my ID is: ThreadId 9
I'm a thread and my ID is: ThreadId 10
I'm a thread and my ID is: ThreadId 7
[0,0,0]

当然,由于GHC版本和比赛的差异,您对同一程序的结果几乎肯定会有不同的身份证号码和订购的详细信息。

所以,你的直觉很好!您的分析只有一个,因为整个表达式g0 `conc` (g1 `conc` (g2 `conc` (return [])))本身并未传递给concurrently,因此您的thread0当然只是主线程,而不是异步库创建的线程

请注意,async提供mapConcurrently以便同时处理任何Traversable,因此您无需使用foldr构建自己的var obj = { hasChanged: false }, description = ""; Object.defineProperty(obj, "description", { get: function() { return description; }, set: function(value) { description = value; obj.hasChanged = true; } }); 。为什么 Haskell中的并行和并发编程中没有提到这个功能,我不确定。它是在async-2.0.1.0中引入的,而Haskell平台版本2012.4.0.0(其中介绍的 PCPH 提到所有代码都经过测试)包括async-2.0.1.3。可能是一个教学上的原因,也许通常在发布方面的延迟加上代码是针对旧版本的平台/库开发的,谁知道。同样的介绍提到“示例代码将随着平台的新版本的发布而更新。”如果您有强烈的感受,请提交erratum