Haskell Concurrent.Channel: 这两个代码有什么区别?
Haskell Concurrent.Channel: What is difference between this two codes?
为什么这个代码
import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TChan
main = do
ch <- newTChanIO
forkIO $ consumer ch 0
forkIO $ consumer ch 1
----------------------
forkIO $ producer ch
----------------------
return ()
producer ch = loop 0
where
loop n = do
atomically $ writeTChan ch n
threadDelay (10^5 :: Int)
loop (n+1)
consumer ch n = forever $ do
v <- atomically $ readTChan ch
print (n, v)
与
的行为方式不同
import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TChan
main = do
ch <- newTChanIO
forkIO $ consumer ch 0
forkIO $ consumer ch 1
----------------------
producer ch
----------------------
return ()
producer ch = loop 0
where
loop n = do
atomically $ writeTChan ch n
threadDelay (10^5 :: Int)
loop (n+1)
consumer ch n = forever $ do
v <- atomically $ readTChan ch
print (n, v)
后面代码的输出是
(0,0)
(1,1)
(1,2)
(1,3)
(1,4)
(0,5)
(0,6)
(1,7)
...
但是,前者的输出只有
(0,0)
我打算 producer
无限期地向通道队列 ch
添加一个值,并且 consumer
无限期地从 ch
.
中获取一个值
后面的代码和我的意图一样,但前者没有。
在事件日志 (ghc-events) 中,块发生在 producer
线程
中的 MVar 上
4775372: cap 0: stopping thread 8 (blocked on an MVar)
为什么之前的代码 (forkIO $ producer ch) 不会无限期地 运行.
http://hackage.haskell.org/package/base-4.10.0.0/docs/Control-Concurrent.html#g:12:
In a standalone GHC program, only the main thread is required to terminate in order for the process to terminate. Thus all other forked threads will simply terminate at the same time as the main thread (the terminology for this kind of behaviour is "daemonic threads").
If you want the program to wait for child threads to finish before exiting, you need to program this yourself.
http://chimera.labs.oreilly.com/books/1230000000929/ch07.html#sec_reminders:
[...] This tells us something important about how threads work in Haskell: the program terminates when main
returns, even if there are other threads still running. The other threads simply stop running and cease to exist after main
returns.
为什么这个代码
import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TChan
main = do
ch <- newTChanIO
forkIO $ consumer ch 0
forkIO $ consumer ch 1
----------------------
forkIO $ producer ch
----------------------
return ()
producer ch = loop 0
where
loop n = do
atomically $ writeTChan ch n
threadDelay (10^5 :: Int)
loop (n+1)
consumer ch n = forever $ do
v <- atomically $ readTChan ch
print (n, v)
与
的行为方式不同import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TChan
main = do
ch <- newTChanIO
forkIO $ consumer ch 0
forkIO $ consumer ch 1
----------------------
producer ch
----------------------
return ()
producer ch = loop 0
where
loop n = do
atomically $ writeTChan ch n
threadDelay (10^5 :: Int)
loop (n+1)
consumer ch n = forever $ do
v <- atomically $ readTChan ch
print (n, v)
后面代码的输出是
(0,0)
(1,1)
(1,2)
(1,3)
(1,4)
(0,5)
(0,6)
(1,7)
...
但是,前者的输出只有
(0,0)
我打算 producer
无限期地向通道队列 ch
添加一个值,并且 consumer
无限期地从 ch
.
后面的代码和我的意图一样,但前者没有。
在事件日志 (ghc-events) 中,块发生在 producer
线程
4775372: cap 0: stopping thread 8 (blocked on an MVar)
为什么之前的代码 (forkIO $ producer ch) 不会无限期地 运行.
http://hackage.haskell.org/package/base-4.10.0.0/docs/Control-Concurrent.html#g:12:
In a standalone GHC program, only the main thread is required to terminate in order for the process to terminate. Thus all other forked threads will simply terminate at the same time as the main thread (the terminology for this kind of behaviour is "daemonic threads").
If you want the program to wait for child threads to finish before exiting, you need to program this yourself.
http://chimera.labs.oreilly.com/books/1230000000929/ch07.html#sec_reminders:
[...] This tells us something important about how threads work in Haskell: the program terminates when
main
returns, even if there are other threads still running. The other threads simply stop running and cease to exist aftermain
returns.