我有一个大文件,用于存储二进制
数据。有多个线程读取和写入这些文件,我当前的设计使用单个Lock
来同步它们。这样,我在 ReadWriteMode
中只为一个文件打开一个 Handle
,并且所有线程在想要执行某些 I/O 时都会争夺该单个锁。
我想通过允许多个读者同时工作来改进这一点。我尝试的是使用 RWLock
并打开多个句柄。 RWLock 将确保只有一个线程修改文件,而允许多个线程(与我打开的句柄一样多,一个编译时常量)同时读取。当尝试运行它时,我对运行时 allows only one 的事实感到震惊。 ReadWriteMode
中的Handle
使文件随时存在。
我该如何解决这种情况?我认为获取/释放 Handle
是一项昂贵的操作,因此在获取 RWLock
后仅以适当的模式打开文件并不是真正的选择。或者也许有一个包提供类似于 Java FileChannel
的 read 的 API和 write方法?
PS:我想支持 32 位架构,因此内存映射 IO 对于大于 4GiB 的文件是不可能的,对吗?
最佳答案
您应该围绕文件句柄和互斥锁构建一个类型。这是一个简单的实现,我认为它可以满足您的目的。
module SharedHandle (SharedHandle, newSharedHandle, withSharedHandle) where
import Control.Concurrent.MVar
import System.IO
data SharedHandle = SharedHandle Handle (MVar ())
newSharedHandle :: IO Handle -> IO SharedHandle
newSharedHandle makeHandle = do
handle <- makeHandle
lock <- newMVar()
return $ SharedHandle handle lock
withSharedHandle :: SharedHandle -> (Handle -> IO a) -> IO a
withSharedHandle (SharedHandle handle lock) operation = do
() <- takeMVar lock
val <- operation handle
putMVar lock ()
return val
这里所做的是我创建了一个新的数据类型,它本质上只是一个文件句柄。唯一的区别是它还带有通过 MVar 实现的自己的单独互斥锁。我提供了两个函数来操作这种新类型。 newSharedHandle 接受一个操作,该操作将创建一个普通句柄并创建一个带有新锁的共享句柄。 withSharedHandle 接受一个对句柄进行操作的操作,锁定共享句柄,执行该操作,然后解锁该句柄。请注意,模块中没有提供构造函数或访问器,因此我们可以放心,没有进程会忘记释放锁,并且我们永远不会在某一特定访问上出现死锁。
用这种新类型替换程序中的所有文件句柄可以解决您的问题。
关于haskell - Haskell 中的并发文件读/写?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23395590/