Haskell,Channels,STM,-threaded,Message Passing

Jon*_*her 5 haskell stm concurrent-programming

我试图使用channels/STM在Haskell中实现消息传递.也许这是一个糟糕的想法,并且有一种更好的方法来实现/使用Haskell中的消息传递.如果是这种情况,请告诉我; 然而,我的任务已经打开了关于并发Haskell的一些基本问题.

我听说过STM很棒的东西,尤其是Haskell中的实现.既然它支持阅读和写作,并且有一些安全上的好处,我认为可以从那里开始.这提出了我最大的问题:是吗

msg <- atomically $ readTChan chan
Run Code Online (Sandbox Code Playgroud)

其中chan是一个TChan Int,导致等待通道等待它的等待?

考虑以下程序:

p chan = do
    atomically $ writeTChan chan 1
    atomically $ writeTChan chan 2

q chan = do
    msg1 <- atomically $ readTChan chan 
    msg2 <- atomically $ readTChan chan
    -- for testing purposes
    putStrLn $ show msg1 
    putStrLn $ show msg2

main = do
    chan <- atomically $ newTChan
    p chan
    q chan
Run Code Online (Sandbox Code Playgroud)

用ghc --make -threaded编译它,然后运行程序,实际上你得到1然后打印到控制台2.现在,假设我们这样做

main = do 
    chan <- atomically $ newTChan
    forkIO $ p chan 
    forkIO $ q chan
Run Code Online (Sandbox Code Playgroud)

代替.现在,如果我们使用 - threaded,它将打印任何内容,1或1后跟2到终端; 但是,如果你不用-threaded编译它总是打印1后跟2.问题2:-threaded和not之间有什么区别?我想它们并不是真正的并发运行,它们只是一个接一个地运行.这与以下内容一致.

现在,按照我的想法,我是否同时运行p和q; 即我对它们进行分叉,它们应该能够以相反的顺序运行.假如

main = do
    chan <- atomically newTChan
    forkIO $ q chan
    forkIO $ p chan
Run Code Online (Sandbox Code Playgroud)

现在,如果我在没有-threaded的情况下编译它,我永远不会打印到控制台.如果我用-threaded编译,我有时会这样做.虽然,很少得到1然后是2 - 通常只有1或没有.我用Control.Concurrent.Chan尝试了这个,并获得了一致的结果.

第二个大问题:频道和分支如何一起播放,以及上述节目中发生了什么?

无论如何,我似乎无法如此天真地模拟使用STM的消息传递.也许Cloud Haskell可以解决这些问题 - 我真的不知道.有关如何获取消息传递缺乏序列化的任何信息~~>写入套接字~~>从套接字读取~~>反序列化将非常感激.

Car*_*ten 9

没有你的想法是正确的 - 这是有用TChan的 - 你只是错过了一个小问题forkIO:

问题是你的主线程不会等待终止创建的线程forkIO(参见此处参考)

所以如果我使用参考文献中给出的提示:

import Control.Concurrent
import Control.Concurrent.STM

p :: Num a => TChan a -> IO ()
p chan = do
    atomically $ writeTChan chan 1
    atomically $ writeTChan chan 2

q chan = do
    msg1 <- atomically $ readTChan chan 
    msg2 <- atomically $ readTChan chan
    -- for testing purposes
    putStrLn $ show msg1 
    putStrLn $ show msg2

main :: IO ()
main = do
    children <- newMVar []
    chan <- atomically $ newTChan
    _ <- forkChild children $ p chan
    _ <- forkChild children $ q chan
    waitForChildren children
    return ()

waitForChildren :: MVar [MVar ()] -> IO ()
waitForChildren children = do
  cs <- takeMVar children
  case cs of
    []   -> return ()
    m:ms -> do
      putMVar children ms
      takeMVar m
      waitForChildren children

forkChild :: MVar [MVar ()] -> IO () -> IO ThreadId
forkChild children io = do
  mvar <- newEmptyMVar
  childs <- takeMVar children
  putMVar children (mvar:childs)
  forkFinally io (\_ -> putMVar mvar ())
Run Code Online (Sandbox Code Playgroud)

它按预期工作:

d:/Temp $ ghc --make -threaded tchan.hs
[1 of 1] Compiling Main             ( tchan.hs, tchan.o )
Linking tchan.exe ...
d:/Temp $ ./tchan.exe 
1
2
d:/Temp $
Run Code Online (Sandbox Code Playgroud)

当然它会继续,如果您切换调用工作pq

  • 是否有任何模块/库可以简化`forkChild` /`waitForChildren`问题? (2认同)