惰性求值如何与 MVars 相互作用?

the*_*ent 6 haskell

假设我有多个线程正在读取文件,并且我想确保在任何时间点只有一个线程正在读取文件。

实现这一点的一种方法是使用 anmvar :: MVar ()并确保互斥,如下所示:

thread = do
   ...
   _ <- takeMVar mvar
   x <- readFile "somefile"  -- critical section
   putMVar mvar ()
   ...
   -- do something that evaluates x. 
Run Code Online (Sandbox Code Playgroud)

以上在严格的语言中应该可以正常工作,但是除非我遗漏了什么,否则我可能会在 Haskell 中遇到这种方法的问题。特别是,由于x线程退出临界区后才进行评估,在我看来,只有在线程执行才会读取该文件putMVar,这首先违背了使用 MVars 的意义,因为多个线程可能会读取同时存档。

我所描述的问题是否真实,如果是,我该如何解决?

Dan*_*ner 9

是的,这是真的。您可以通过避免base使用unsafeInterleaveIO. 我没有完整的列表,但至少是readFile, getContents, hGetContents。不做懒惰 IO 的 IO 操作——比如hGethGetLine——很好。

如果您必须使用惰性 IO,则在关键部分内的 IO 操作中完全评估其结果,例如通过组合rnfevaluate

关于相关事物的其他一些评论,但这并不是对这个问题的直接回答:

  • 懒惰和懒惰 IO 是真正独立的概念。它们碰巧共用一个名字,因为人类懒于命名。大多数IO 操作不涉及惰性 IO,也不会遇到此问题。

  • 有一个相关的问题是将未MVar评估的纯计算填充到您的并意外地在与您预期不同的线程上评估它,但是如果您避免延迟 IO,那么在错误的线程上评估只是一个性能错误,而不是实际的语义错误。