Pregunta ¿El archivo concurrente lee / escribe en Haskell?


Tengo un archivo grande donde almaceno Binary datos. Hay varios hilos que leen y escriben estos archivos, y mi diseño actual los sincroniza usando una sola Lock. De esta manera, solo tengo una Handle en ReadWriteMode abierto para un archivo, y todos los subprocesos luchan por ese único bloqueo cuando tienen ganas de hacer alguna E / S

Me gustaría mejorar esto permitiendo que varios lectores trabajen simultáneamente. Lo que intenté fue usar un RWLock y teniendo múltiples manijas abiertas. los RWLock aseguraría que solo un subproceso modifique el archivo, mientras que muchos subprocesos (tantos como los que tengo manejadores abiertos, una constante de compilación) pueden leer simultáneamente. Al intentar ejecutar esto, me sorprendió el hecho de que el tiempo de ejecución permite solo una  Handle en ReadWriteMode Para existir para un archivo en cualquier momento.

¿Cómo puedo resolver esta situación? Supongo que obteniendo / liberando un Handle es una operación costosa, así que solo abra el archivo en el modo apropiado después de adquirir el RWLock No es realmente una opción. O tal vez hay un paquete que ofrece una API similar a Java FileChanneles leer y escribirmétodos?

PD: me gustaría admitir arquitecturas de 32 bits, por lo que el IO asignado a la memoria no es posible para archivos> 4GiB, ¿verdad?


6
2018-04-30 18:35


origen


Respuestas:


Así que tu problema es que no quieres usar estado Handles (donde el estado es la ubicación actual en el archivo)? En ese caso, necesitas pread y pwrite, Supongo.

man pread

Para Haskell vinculante: http://hackage.haskell.org/package/unix-bytestring-0.3.7.2/docs/System-Posix-IO-ByteString.html

Para ver un ejemplo de uso, puedes mirar aquí: https://github.com/errge/PrefetchFS/blob/master/PrefetchHandle.hs


1
2018-05-02 09:45



Debe construir un tipo alrededor del identificador de archivo y un bloqueo de exclusión mutua. Aquí hay una implementación simple que creo que funcionaría para sus propósitos.

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

Lo que está sucediendo aquí es que he creado un nuevo tipo de datos que, en esencia, es solo un manejador de archivo. La única diferencia es que también viene con su propio bloqueo mutex individual implementado con un MVar. He proporcionado dos funciones para operar en este nuevo tipo. newSharedHandle toma una operación que crearía un identificador normal y creó un identificador compartido con un bloqueo nuevo. withSharedHandle realiza una operación para operar en los controladores, bloquea el controlador compartido, realiza la operación y luego desbloquea el controlador. Tenga en cuenta que el constructor o los elementos de acceso no se proporcionan desde el módulo, por lo que podemos estar seguros de que nunca se olvidará de ningún proceso para liberar el bloqueo y nunca tendremos interbloqueos en un acceso en particular.

Reemplazar todos los manejadores de archivos en su programa con este nuevo tipo podría resolver su problema.


1
2018-04-30 21:34