2014-04-30 13 views
6

Mam duże pliki, w których przechowuję dane Binary. Istnieje wiele wątków do czytania i zapisywania tych plików, mój obecny projekt synchronizuje je przy użyciu pojedynczego Lock. W ten sposób mam tylko jedną otwartą dla pliku Handle w ReadWriteMode, a wszystkie wątki walczą o tę pojedynczą blokadę, kiedy mają ochotę wykonać niektóre operacje wejścia/wyjścia.Równoczesne czytanie/zapisywanie w Haskell?

Chciałbym poprawić tę sytuację, umożliwiając jednoczesną pracę wielu czytników. Próbowałem użyć RWLock i otworzyć wiele uchwytów. Numer RWLock zapewnia, że ​​tylko jeden wątek modyfikuje plik, podczas gdy wiele wątków (tyle, ile mam otwartych uchwytów, stała czasu kompilacji) może czytać jednocześnie. Kiedy próbowałem to uruchomić, uderzył mnie fakt, że plik runtime allows only oneHandle w pliku istnieje w dowolnym momencie.

Jak mogę rozwiązać tę sytuację? Zakładam, że uzyskanie/zwolnienie Handle jest kosztowną operacją, więc samo otwarcie pliku w odpowiednim trybie po nabyciu RWLock nie jest tak naprawdę opcją. A może jest pakiet oferujący API podobny do metod Javy FileChannel 'read i write?

PS: Chciałbym obsługiwać 32-bitowe architektury, więc IO z mapami pamięci nie jest możliwe dla plików> 4GiB, prawda?

+0

Czy próbowałeś za pomocą dowolnego równolegle I/O biblioteki do odczytu zapisu plików? Jest ich kilka, HDF5, PNetCDF, SIONlib ... wszystkie obsługują równoczesne czytanie/zapisywanie do plików równolegle w systemach pamięci współdzielonej i rozproszonej i wszystkie one skalują się całkiem dobrze do rdzenia O (10^4) . – gnzlbg

Odpowiedz

1

Twój problem polegał na tym, że nie chcesz używać stanowych Handle s (gdzie stan jest bieżącą lokalizacją w pliku)? W takim przypadku potrzebujesz pread i pwrite, jak sądzę.

man pread

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

Dla przykładu użytkowania, można zajrzeć tutaj: https://github.com/errge/PrefetchFS/blob/master/PrefetchHandle.hs

+0

To wygląda jak idealny mecz, spróbuję go krótko. – Waldheinz

1

Powinieneś zbudować typ wokół uchwytu pliku i blokady mutex. Oto prosta implementacja, która według mnie zadziałałaby dla twoich celów.

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 

Co mam na myśli, to stworzyłem nowy typ danych, który w istocie jest tylko uchwytem pliku. Jedyną różnicą jest to, że posiada również własny blokadę mutex zaimplementowaną z MVar. Dostarczyłem dwie funkcje do działania na tym nowym typie. newSharedHandle wykonuje operację, która utworzyłaby normalny uchwyt i utworzyła wspólny uchwyt ze świeżą blokadą. withSharedHandle wykonuje operację operowania na uchwytach, blokuje udostępniony uchwyt, wykonuje operację, a następnie odblokowuje uchwyt. Zauważ, że konstruktor lub akcesory nie są dostarczane z modułu, więc możemy być pewni, że żaden proces nigdy nie zapomni zwolnić blokady i nigdy nie dostaniemy zakleszczeń na jednym konkretnym dostępie.

Zastąpienie wszystkich uchwytów plików w programie tym nowym typem może rozwiązać problem.

+0

Czy to już nie jest to, co już robię? Nie rozumiem, w jaki sposób pozwoliłoby to na równoczesne działanie wielu czytników, ponieważ wszystkie one są przeznaczone dla pojedynczego 'MVar' (który jest mniej lub bardziej używany jako' Lock' w tym kodzie). Ponadto nie jest to wyjątek bezpieczny.;-) – Waldheinz

+0

Myślałem, że chcesz mieć wiele plików zapisanych na raz, ale indywidualnie je zablokuj, aby nie zablokować całego zestawu. Jeśli chcesz pisać do tego samego pliku w tym samym czasie, czy nie jest dobrze mieć niezaznaczone warunki wyścigu? Posix pozwala już na dołączanie wielu procesów do pliku bez blokowania. W skrócie, jaki jest problem z twoim programem, który nie blokuje niczego i pozwala szybszemu procesowi wygrać wyścig i być pierwszym, który napisze? – mmachenry

+0

Och, może powinienem był to wyraźnie powiedzieć: Moje pliki mają stały rozmiar i zapisuję/odczytuję losowe przesunięcia w pliku. Moim problemem jest wyścig pomiędzy szukaniem poprawnego przesunięcia i faktycznym wykonywaniem operacji wejścia/wyjścia, gdy wiele wątków ma dostęp do pojedynczego pliku. Mam tylko dwa pliki, ale dziesiątki czytelników/pisarzy. – Waldheinz