假设我有多个线程正在读取文件,并且我想确保在任何时间点只有一个线程正在读取文件。
实现这一点的一种方法是使用 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 的意义,因为多个线程可能会读取同时存档。
我所描述的问题是否真实,如果是,我该如何解决?
是的,这是真的。您可以通过避免base使用unsafeInterleaveIO. 我没有完整的列表,但至少是readFile, getContents, hGetContents。不做懒惰 IO 的 IO 操作——比如hGet或hGetLine——很好。
如果您必须使用惰性 IO,则在关键部分内的 IO 操作中完全评估其结果,例如通过组合rnf和evaluate。
关于相关事物的其他一些评论,但这并不是对这个问题的直接回答:
懒惰和懒惰 IO 是真正独立的概念。它们碰巧共用一个名字,因为人类懒于命名。大多数IO 操作不涉及惰性 IO,也不会遇到此问题。
有一个相关的问题是将未MVar评估的纯计算填充到您的并意外地在与您预期不同的线程上评估它,但是如果您避免延迟 IO,那么在错误的线程上评估只是一个性能错误,而不是实际的语义错误。