2013-01-14 34 views
16

Używam od pewnego czasu ReaderWriterLockSlim i spełnił on moje potrzeby do tego momentu. W miarę dostrajania mojej aplikacji, stwierdzam, że ReaderWriterLockSlim jest nieznacznie nieoptymalny dla mojego przypadku użycia.Czy istnieje odpowiednik ReaderWriterLockSlim, który faworyzuje czytelników?

Zgodnie z dokumentacją (i moim doświadczeniem) faworyzuje pisarzy nad czytnikami (to znaczy, gdy czytelnicy i pisarze są w kolejce, autorzy będą mieli pierwszeństwo). Potrzebuję jednak odpowiednika, który faworyzuje czytelników. Rozumiem skutki uboczne takiego składnika (zwłaszcza problem głodu pisarza).

Czy są jakieś ekwiwalenty gotowe do produkcji, na które można wskazać? Dzięki.

+3

Brak kodu nigdy nie może zostać udowodniony jednoznacznie. Ale nie, to mało prawdopodobne. Unikaj pytań o zakupy. –

+0

Jeśli chcesz faworyzować odczyty, dlaczego po prostu nie zastąpisz wewnętrznej listy zaktualizowanym klonem? Twój kod zostanie zablokowany, ale nieco cięższy od aktualizacji. – jgauffin

+1

Tak, brzmi to tak, jakbyś mógł rozwiązać to albo z kopią, jak sugeruje jgauffin, albo jeśli struktura danych jest zbyt duża dla taniej kopii, z buforem zapisu, więc zapisy są rzadsze. Następnie można po prostu dostosować saldo odczytu/zapisu, zwiększając lub zmniejszając czas, aby opróżnić bufor. –

Odpowiedz

6

Według MSDN program ReaderWriterLockSlim faworyzuje pisarzy. Oznacza to, że jeśli w kolejce znajdują się czytniki i piszący, pisarze będą mieli pierwszeństwo.

Może to spowodować głód czytelnika, kod testowy do odtworzenia to here. Zakładam, że głodzenie może się zdarzyć tylko wtedy, gdy pisanie jest długotrwałe, z włączonym przełącznikiem kontekstu wątku. Przynajmniej jest zawsze reprodukowane na moim komputerze, więc proszę powiedz mi, czy się mylę.

Z drugiej strony, ReaderWriterLock z .net 2.0 nie wytwarza ani głodu czytelników, ani pisarzy, kosztem obniżonej wydajności. Here to zmodyfikowany kod z poprzedniej próbki, aby pokazać, że nie ma żadnego głodu.

Powracając do pytania - zależy to od tego, jakie funkcje wymagają blokady RW. Blokady rekursywne, obsługa wyjątków, limity czasu - najbardziej zbliżone do jakości produkcji Blokada RW, która obsługuje wszystkie powyższe, i preferuje czytelników prawdopodobnie będzie ReaderWriterLock.

Możesz również przyjąć kod z artykułu wiki opisującego first readers-writers problem, ale oczywiście musisz zaimplementować wszystkie wymagane funkcje z góry ręcznie, a wdrożenie będzie miało problem z pisarzem-głodem.

Blokada rdzeń może prawdopodobnie wyglądać następująco:

class AutoDispose : IDisposable 
{ 
    Action _action; 
    public AutoDispose(Action action) 
    { 
    _action = action; 
    } 
    public void Dispose() 
    { 
    _action(); 
    } 
} 

class Lock 
{ 
    SemaphoreSlim wrt = new SemaphoreSlim(1); 
    int readcount=0; 

    public IDisposable WriteLock() 
    { 
    wrt.Wait(); 
    return new AutoDispose(() => wrt.Release()); 
    } 

    public IDisposable ReadLock() 
    { 
    if (Interlocked.Increment(ref readcount) == 1) 
     wrt.Wait(); 

    return new AutoDispose(() => 
    { 
     if (Interlocked.Decrement(ref readcount) == 0) 
     wrt.Release(); 
    }); 
    } 
} 

Porównywanie wydajności 3 implementacjach, stosując 3 czytelnika i 3 wątki pisarz, za pomocą prostych w pamięci operacji (za pomocą operacji długo blokuje przyniosłoby czytelnika głód na RWLockSlim i pisarz-głód na zlecenie zamka):

Performance comparison

i upewnić się, że pętla obciążenie nie jest rozwijana przez kompilator, ale mogą istnieć inne pułapek nie jestem świadomy, więc t wykonaj te pomiary z przymrużeniem oka. Kod źródłowy do testów to here.

+0

wspaniała i bardzo szczegółowa odpowiedź! bardzo doceniane - przyjrzę się. –

Powiązane problemy