Haskell、通道、STM、线程、消息传递

2024-02-12

我正在尝试使用 Channels/STM 在 Haskell 中实现消息传递。也许这是一个糟糕的想法,并且有更好的方法在 Haskell 中实现/使用消息传递。如果是这种情况,请告诉我;然而,我的探索提出了一些关于并发 Haskell 的基本问题。

我听说过有关 STM 的伟大事情,特别是在 Haskell 中的实现。由于它支持读取和写入,并且具有一些安全优势,因此我认为应该从这里开始。这提出了我最大的问题:

msg <- atomically $ readTChan chan

其中 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

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

main = do 
    chan <- atomically $ newTChan
    forkIO $ p chan 
    forkIO $ q chan

反而。现在,如果我们使用 -threaded,它要么什么也不打印,要么打印 1,要么打印 1 后跟 2 到终端;但是,如果不使用 -threaded 进行编译,它总是打印 1 后跟 2。 问题 2:-threaded 和非 -threaded 之间有什么区别?我想它们并不是真正作为并发事物运行,它们只是一个接一个地运行。这与下面的内容是一致的。

现在,在我的想法中,如果我让 p 和 q 同时运行;也就是说,我对它们进行了分叉,它们应该能够以相反的顺序运行。假如

main = do
    chan <- atomically newTChan
    forkIO $ q chan
    forkIO $ p chan

现在,如果我在没有 -threaded 的情况下编译它,我永远不会在控制台上打印任何内容。如果我使用 -threaded 进行编译,有时会这样做。尽管如此,获得 1 后又获得 2 的情况非常罕见——通常只有 1 或什么都没有。我也用 Control.Concurrent.Chan 尝试过这一点,并得到了一致的结果。

第二个大问题:通道和分叉如何一起发挥作用,上面的程序中发生了什么?

无论如何,看来我不能这么天真地用STM来模拟消息传递。也许 Cloud Haskell 是解决这些问题的一个选择——我真的不知道。任何有关如何在序列化~~>写入套接字~~>从套接字读取~~>反序列化的情况下传递消息的任何信息都将受到极大的赞赏。


不,你的想法是对的——这就是什么TChans 代表 - 你只是错过了一个小点forkIO:

问题是你的主线程不会等待用创建的线程终止forkIO (请参阅此处以供参考 https://hackage.haskell.org/package/base-4.8.0.0/docs/Control-Concurrent.html#g:12)

所以如果我使用hint参考文献中给出:

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 ())

它按预期工作:

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 $

当然,如果您将呼叫切换到,它会继续工作p and q too

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Haskell、通道、STM、线程、消息传递 的相关文章

随机推荐

  • 使用 jQuery 切换类

    当用户单击链接时 我需要隐藏 div html 是这样的 div class item div class entry Lorem ipsum div a href class commentsToggle Show hide commen
  • Ionic - 如何设置 高度,以便它在所有分辨率设备中自动调整?

    我的代码如下
  • 如何在关闭时完全删除对话框

    当 ajax 操作失败时 我创建一个包含错误的新 div 然后将其显示为对话框 当对话框关闭时 我想完全销毁并再次删除 div 我怎样才能做到这一点 我的代码目前看起来像这样 div We failed div dialog title E
  • 在Java中查找数组中的元素

    Java 是否有内置函数允许我线性搜索数组中的元素 还是必须只使用 for 循环 有一个contains列表的方法 所以你应该能够这样做 Arrays asList yourArray contains yourObject 警告 这可能不
  • Flutter - 英雄动画不适用于选项卡导航器

    我是颤振新手 我正在使用英雄小部件为浮动按钮制作动画 我有底部导航 我必须使用选项卡导航器打开页面 但英雄动画不起作用 我使用了所有可能的解决方案 但英雄动画仍然不适用于页面路由 这是我的代码片段 FloatingActionButton
  • 无法删除全局包

    尝试删除全局包 但似乎没有删除它 eslint v v1 10 3 npm uninstall eslint g sudo npm uninstall eslint g eslint v v1 10 3 sudo eslint v v1 1
  • 如何使用之前输入的值填充自定义结帐字段,例如默认的 WooCommerce 结帐字段?

    我使用以下代码添加了一个自定义字段 add action woocommerce before order notes bbloomer add custom checkout field function bbloomer add cus
  • 在python中读取15M行csv文件的有效方法

    对于我的应用程序 我需要读取多个文件 每个文件有 15 M 行 将它们存储在 DataFrame 中 并将 DataFrame 保存为 HDFS5 格式 我已经尝试过不同的方法 特别是具有 chunksize 和 dtype 规范的 pan
  • 获取调用者类

    我正在编写 Logger 并在自动添加类名时遇到问题 我从中调用了 print log 方法 例如这样的事情 class Logger def self print log string puts Time now strftime T c
  • 美国电话号码验证

    我有一个网站表单 需要输入美国电话号码以供后续使用 在这种情况下这是非常有必要的 我想尝试消除用户输入垃圾数据330 000 0000 我已经看到了第三方为您验证电话号码的一些选项 但是我不知道这是否是这种情况的最佳选择 但是 如果您使用过
  • PyQt 项目视图自定义拖放

    我正在 QTableView 中进行自定义拖放实现 当我拖动一个单元格并将其放在另一个单元格上时 我想根据拖动的内容和放置的位置手动更改模型中的一些数据 我怎样才能做到这一点 我已经阅读了所有 Qt 文档 但我完全迷失了 特别是通过拖放 C
  • Couchbase 中的存储桶密码

    我正在创建一个使用 springboot 和 Couchbase 进行反应式编程的演示项目 我在 application properties 文件中设置了以下属性 spring couchbase bootstrap hosts loca
  • APK 0(零)设备兼容性

    我正在生成一个要在商店上发布的 APK 它是现有应用程序的更新 上传到 Google Play Console 后 支持的 Android 设备 0 台设备 这是我的清单
  • vue js如何使用方法将数据从父组件、v-for循环列表传递到子组件

    我试图实现在子组件 模态组件 中显示每个项目收据数组的项目列表 但一直无法这样做 方法display receipts 是将receipts modal的数据值改为true 我可以在哪里放置 v bind 来传递数组 任何帮助深表感谢 Pa
  • 使用networkx从图中删除边

    我正在尝试转换DiGraph成n叉树并按层序或BFS显示节点 我的树与此类似 但更大 为简单起见 使用以下示例 G networkx DiGraph G add edges from n n1 n n2 n n3 G add edges f
  • 是否可以使用服务帐户访问Provisioning API?

    我的服务帐户范围是 https apps apis google com a feeds user https apps apis google com a feeds user 和 DriveScope DRIVE 我在我的服务帐户 ID
  • VS2015:警告MSB3884:找不到规则集文件

    将我的 WinForms VS2013 项目升级到 VS2015 后 我开始看到 MSB3884 找不到规则集文件 警告 Google 搜索发现了一篇 MSDN 文章 Stack Overflow 文章以及许多其他网站都指向了该文章 类似问
  • R可以识别Excel文件是否有注释单元格吗?

    我有一张 Excel 表格 xlsx 其中有一些注释的单元格 导入R后 R有什么办法可以识别注释的单元格吗 因为我必须仅对注释的单元格使用一些 if else 条件 Let s say we have this file test xlsx
  • 以逗号或分号分隔的自动完成文本框

    我想要一个TextBox支持自动完成 并允许用户输入以逗号或分号分隔的多个单词 并为每个单词提供建议 我有一个标准TextBox with textBox AutoCompleteCustomSource AddRange new appl
  • Haskell、通道、STM、线程、消息传递

    我正在尝试使用 Channels STM 在 Haskell 中实现消息传递 也许这是一个糟糕的想法 并且有更好的方法在 Haskell 中实现 使用消息传递 如果是这种情况 请告诉我 然而 我的探索提出了一些关于并发 Haskell 的基