无锁编程在 Haskell 中是微不足道的。拥有需要由多个线程修改的共享数据的最简单方法是从任何普通的 haskell 类型(列表、映射、可能,任何您需要的)开始,并将其放在 IORef 中。完成此操作后,您就可以使用 atomicModifyIORef 就地执行修改,保证几乎不需要任何时间。
type MyDataStructure = [Int]
type ConcMyData = IORef MyDataStructure
main = do
sharedData <- newIORef []
...
atomicModifyIORef sharedData (\xs -> (1:xs,()))
这样做的原因是存储了指向最终将评估 IORef 内部结果的 think 的指针,并且每当线程从 IORef 读取时,它们都会获得 thunk,并根据需要评估尽可能多的结构。由于所有线程都可以读取相同的 thunk,因此它只会被评估一次(如果它被多次评估,则保证总是以相同的结果结束,所以并发评估是可以的)。我相信这是正确的,但我很高兴得到纠正。
带回家的信息是,这种抽象只能用纯语言轻松实现,其中事物的价值永远不会改变(当然,除非它们改变了,像 IORef、MVars 和 STM 类型这样的类型)。Haskell 数据结构的写时复制特性意味着修改后的结构可以与原始结构共享大量数据,而只分配结构中的任何新数据。
我认为我没有很好地解释这是如何工作的,但我明天会回来澄清我的答案。
有关更多信息,请参阅Microsoft Research 的 Simon Marlow(也是主要的 GHC 实现者之一)在 Haskell 中讨论多核编程的幻灯片。