gpt4 book ai didi

线程之间的 Haskell 求值同步

转载 作者:行者123 更新时间:2023-12-03 14:13:09 25 4
gpt4 key购买 nike

我试图了解 GHC Haskell 如何在线程之间同步“基本”值(即不是 IORef、TVar 等)的计算。我已经搜索了有关此的信息,但没有找到任何明确的信息。
以下面的示例程序为例:

import Control.Concurrent

expensiveFunction x = sum [1..x] -- Just an example

val = expensiveFunction 12345

thread1 = print val

thread2 = print val

main = do
forkOS thread1
forkOS thread2
我知道值 va​​l 最初将由未评估的闭包表示。为了打印 val,程序必须首先评估它。一旦评估了顶级绑定(bind),就不需要再次评估它。
  • “val”的表示是否由单独的线程共享?
  • 如果由于某种原因线程1首先完成评估,它可以通过交换指针将最终计算值传递给线程2吗?那将如何同步?
  • 如果线程 1 正忙于评估线程 2 何时需要该值,线程 2 是等待它完成还是他们都争先恐后地评估它?
  • 最佳答案

    在 GHC 编译的程序中,值经过三个(-ish)评估阶段:

  • 咚咚。这是他们开始的地方。
  • 黑洞。当被强制时,一个 thunk 被转换为一个黑洞并开始计算。其他请求黑洞值的线程会将自己添加到黑洞更新时的通知列表中。 (此外,如果 thunk 本身尝试访问黑洞,它将短路到异常而不是永远等待。)
  • 评估。当计算完成时,它的最后一项任务是将黑洞更新为一个普通值(好吧,无论如何,WHNF 值)。

  • 在这些阶段转换期间更新的指针与其他线程共享,不受竞争条件的保护。这意味着,在极少数情况下,两个(或更多)线程都可能在阶段 1 中看到一个指针,并且两者都执行 1 -> 2 转换;在这种情况下,两者都将评估 thunk,并且转换 2 -> 3 也将发生两次。不过,值得注意的是,1 -> 2 转换通常比它要替换的计算快得多(本质上只是一两次内存访问),部分原因是竞争难以触发。
    因为语言是纯粹的,赛跑的线索会得出相同的答案。所以这里没有语义上的困难。但在极少数情况下,可能会重复一些工作。非常非常罕见的是,每次 1 -> 2 转换时锁定的开销会比这种轻微的重复更好。 (如果您发现这种情况,请考虑手动保护对共享的任何昂贵事物的评估!)
    推论:必须非常小心不安全的 IO a -> a函数族;一些保证结果的评估同步 a有些没有。如果您的 IO a Action 并不像你 promise 的那么纯粹,一场比赛导致它被执行两次,各种奇怪的黑森虫都会发生。

    关于线程之间的 Haskell 求值同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65509665/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com