2012-01-03 12 views
7

W moim programie symuluję system N-body dla dużej liczby iteracji. Dla każdej iteracji generuję zestaw współrzędnych 6N, które muszę dołączyć do pliku, a następnie użyć do wykonania następnej iteracji. Kod jest napisany w C++ i obecnie korzysta z metody ofstreamwrite() do zapisywania danych w formacie binarnym w każdej iteracji.Najszybszy sposób zapisu danych podczas ich tworzenia

Nie jestem ekspertem w tej dziedzinie, ale chciałbym poprawić tę część programu, ponieważ jestem w trakcie optymalizacji całego kodu. Uważam, że opóźnienie związane z zapisywaniem wyniku obliczeń w każdym cyklu znacznie spowalnia działanie oprogramowania.

Jestem zdezorientowany, ponieważ nie mam doświadczenia w programowaniu równoległym i we/wy dla plików o niskim poziomie. Myślałem o pewnych abstrakcyjnych technik Wyobrażałem mogłaby wdrożyć, ponieważ jestem programowanie dla współczesnego (ewentualnie wielordzeniowych) maszyny z uniksach:

  • Zapisywanie danych w pliku w kawałki n iteracjach (nie wydaje być lepsze sposoby, aby kontynuować ...)
  • parallelizing kod z OpenMP (jak faktycznie realizują bufor tak, że nici są synchronizowane prawidłowo i nie pokrywają się?)
  • Korzystanie mmap (rozmiar pliku może być ogromny, rzędu GB, czy to podejście jest wystarczająco solidne?)

Jednak nie wiem, jak najlepiej je wdrożyć i odpowiednio je połączyć.

+0

Jakie jest twoje pytanie? –

+6

"Uważam, że opóźnienie związane z zapisywaniem wyniku obliczeń w każdym cyklu znacznie spowalnia działanie oprogramowania." czy czujesz to czy sprofilowałeś swój kod? –

+0

Czy profilowałeś kod, aby upewnić się, że twoje odczucia dotyczące opóźnień są prawidłowe? – Grizzly

Odpowiedz

3

Oczywiście pisanie do pliku przy każdej iteracji jest nieefektywne i najprawdopodobniej spowalnia działanie komputera. (z reguły zależy to od przypadku aktuariusza)

Należy użyć wzoru projektu producer ->consumer. Zostaną połączone kolejką, jak przenośnik taśmowy.

  • Producent będzie starał się produkować tak szybko, jak to możliwe, tylko spowalniając, jeśli konsument nie może sobie z tym poradzić.
  • Konsument będzie próbował "skonsumować" tak szybko, jak tylko możliwe.

Dzięki rozdzieleniu dwóch można zwiększyć wydajność, ponieważ każdy proces jest prostszy i ma mniej zakłóceń od drugiego.

  • Jeśli producent jest szybsze, trzeba poprawić konsumenta w danym przypadku poprzez pisanie do pliku w najbardziej efektywny sposób, kawałek po kawałku najprawdopodobniej (jak powiedział)
  • Jeżeli konsument jest szybsza , musisz ulepszyć producenta, najprawdopodobniej poprzez zrównoleglenie go, jak powiedziałeś.

Istnieje nie trzeba, aby zoptymalizować oba. Optymalizuj tylko najwolniej (wąskie gardło).

Praktycznie używasz wątków i synchronizowanej kolejki między nimi. Aby uzyskać wskazówki dotyczące implementacji, spójrz na: here, szczególnie § 18.12 "Wzór Producent-Konsument".

O zarządzaniu przepływem, będziesz musiał dodać trochę więcej komplikacji, wybierając "maksymalny rozmiar kolejki" i sprawiając, że producenci oczekują, jeśli kolejka ma za mało miejsca. Strzeż się więc zakleszczeń, zakoduj go ostrożnie. (patrz link wikipedia, który dałem o tym)

Uwaga: Dobrze jest używać wątków wspomagających, ponieważ wątki nie są bardzo przenośne. (no, są one, ponieważ C++ 0x, ale dostępność C++ 0x nie jest jeszcze dobra)

+0

. Ale biorąc pod uwagę rozmiar danych, jak postępować w przypadku, gdy producent jest tak szybki, że produkuje coś, czego nie można zapisać w pamięci, zanim konsument zdoła go zapisać na dysku? –

+2

@Fiat Lux Cóż, jeśli produkujesz dane szybciej niż można je przechowywać w systemie plików, masz dość podstawowy problem całkowicie niezależny od jakichkolwiek sztuczek oprogramowania, które robisz. Jeśli przepustowość jest zbyt mała, prędzej czy później zabraknie miejsca w buforze, a potem i tak będziesz musiał sobie z tym poradzić. – Voo

+1

@FiatLux dlatego właśnie powiedziałem, że "procesor ... zwalnia, jeśli konsument nie może sobie z tym poradzić". Edytowałem, aby dodać link do przykładu wdrożenia + sugerowane usprawnienia. Musisz kazać producentom czekać, jeśli pamięć jest pełna. – Offirmo

1

Lepiej podzielić operację na dwa niezależne procesy: data-producing i file-writing. Data-producing użyłby bufora dla przechodzenia danych w sposób iteracyjny, a file-writing używałby kolejki do przechowywania żądań zapisu. Następnie, data-producing po prostu wysłałby żądanie zapisu i kontynuował, podczas gdy file-writing poradziłby sobie z pisaniem w tle.

Zasadniczo, jeśli dane są produkowane o wiele szybciej, niż jest to możliwe, szybko zatrzymasz większość z nich w buforze. W takim przypadku twoje rzeczywiste podejście wydaje się być całkiem rozsądne, ponieważ niewiele można zrobić programowo, aby poprawić sytuację.

+0

Dlaczego myślisz, że możesz lepiej buforować niż blokowanie pamięci podręcznej systemu operacyjnego? –

+0

@SteveC Ponieważ ogólnie lepiej jest wdrożyć algorytm w deterministyczny sposób, niż polegać na funkcjach zależnych od implementacji. Mam na myśli, blokowanie pamięci podręcznej * jest * dobre, ale może lub nie pasuje do konkretnej sytuacji. Może nie być tak przenośny, może nie być tak szybki, itp., A OP nie był zbyt szczegółowy i tak :) – vines

+0

W takim przypadku nie powinieneś przechodzić przez dwie warstwy buforowania, ale po prostu obejść system plików i napisać do surowy dysk. To "bardziej deterministyczny" i można "dopasować go do konkretnej sytuacji". Osobiście wątpię, byś mógł wykonać lepszą pracę niż autorzy systemów plików. –

0

„Korzystanie mmap (rozmiar pliku może być ogromna, rzędu GBS, jest to podejście solidna wystarczy?)”

mmap jest metoda OS za programy ładowania, bibliotek dzielonych i plik stronicowania/wymiany - jest tak solidny, jak wszystkie inne operacje we/wy i ogólnie wyższa wydajność.

ALE na większości systemów operacyjnych jest to złe/trudne/niemożliwe do rozszerzenia rozmiaru zmapowanego pliku, gdy jest on używany. Więc jeśli znasz rozmiar danych lub czytasz tylko, to jest świetne. Log/dump, który ciągle dodajesz do niego jest mniej sutiable - chyba że znasz jakiś maksymalny rozmiar.

+0

Znam rozmiar danych, ale nie będzie problemu z systemami 32-bitowymi, jeśli mam plik o gigabajtach? –

+0

@Fiat - to duża zaleta mmap. Możesz odwzorować wiele widoków w pliku z przesunięciami, dzięki czemu możesz użyć okna, aby uzyskać dostęp do dowolnej części pliku, tak dużej jak pozwala na to FS. Szczegóły zależą od systemu operacyjnego OS –

1

Jeśli nie chcesz grać z robieniem rzeczy w różnych wątkach, możesz spróbować użyć opcji aio_write(), która pozwala na asynchroniczne pisze. Zasadniczo dajesz systemowi operacyjnemu bufor do zapisu, a funkcja natychmiast zwraca i kończy zapis, podczas gdy twój program jest kontynuowany, możesz sprawdzić później, czy zapis został zakończony.

To rozwiązanie wciąż jest dotknięte problemem producenta/konsumenta wymienionym w innych odpowiedziach, jeśli algorytm generuje dane szybciej niż można je zapisać, w końcu zabraknie pamięci do przechowywania wyników między algorytmem a zapisem , więc musisz spróbować i zobaczyć, jak to działa.

Powiązane problemy