23

Próbuję poprawić wydajność skryptu po jego uruchomieniu w usłudze WWW. Jest przeznaczony do parsowania dużych plików tekstowych w przeglądarce bez awarii. Wszystko działa całkiem nieźle, ale zauważam poważną różnicę w wydajności dużych plików podczas korzystania z web-pracownika.Dlaczego wydajność pracownika WWW gwałtownie spada po 30 sekundach?

Przeprowadziłem więc prosty eksperyment. Dwa razy uruchomiłem skrypt na tym samym wejściu. Pierwsze uruchomienie wykonało skrypt w głównym wątku strony (brak pracowników WWW). Naturalnie powoduje to zamrożenie strony i przestaje reagować. W drugim uruchomieniu skrypt wykonałem w usłudze WWW.

Dla małych plików w tym eksperymencie (< ~ 100 MB), różnica wydajności jest znikomy. Jednak na dużych plikach, parsowanie trwa około 20x dłużej w wątku roboczego: Oczekuje

Performance of both scenarios on same graph

Niebieska Linia. Należy jedynie około 11 sekund, aby przetworzyć plik, a wydajność jest dość stabilny:

Performance of script without web worker

Czerwona linia jest wykonanie wewnątrz pracownika internetowej. Jest o wiele bardziej zaskakujące:

Performance of script in web worker

poszarpanej linii przez pierwsze 30 sekund jest normalne (Iglica jest spowodowany niewielkim opóźnieniem wysyłania wyników do głównego wątku po każdym fragmencie pliku jest analizowany). Jednak parsowanie spowalnia raczej gwałtownie po 30 sekundach. (Zauważ, że do pracy używam tylko jednego pracownika WWW, nigdy więcej niż jednego wątku roboczego na raz.)

Potwierdziłem, że opóźnienie wynosi , a nie w wysyłaniu wyników do głównego wątku wątek z postMessage(). Spowolnienie jest w the tight loop parsera, który jest całkowicie synchroniczny. Z powodów, których nie potrafię wyjaśnić, pętla jest drastycznie spowolniona, a po 30 sekundach staje się wolniejsza.

Ale dzieje się tak tylko w przeglądarce internetowej. Uruchamianie tego samego kodu w głównym wątku, jak widać powyżej, przebiega bardzo sprawnie i szybko.

Dlaczego tak się dzieje? Co mogę zrobić, aby poprawić wydajność? (Nie oczekuję, że ktokolwiek w pełni zrozumie wszystkie 1200 wierszy kodu w tym pliku. Jeśli to zrobisz, to jest niesamowite, ale mam wrażenie, że jest to bardziej związane z pracownikami sieciowymi niż z moim kodem, ponieważ działa dobrze w głównym wątek.)

System: używam Chrome 35 na Mac OS 10.9.4 z 16 GB pamięci; czterordzeniowy procesor Intel Core i7 2,7 GHz z pamięcią podręczną L2 o pojemności 256 KB (na rdzeń) i pamięcią podręczną L3 o pojemności 6 MB. Rozmiar pliku wynosi około 10 MB.

Aktualizacja: prostu próbowałem go na Firefox 30 i to zrobił nie doświadczenie tego samego spowolnienie w wątku roboczego (ale to był wolniejszy niż Chrome po uruchomieniu w głównym wątku). Jednak próba wykonania tego samego eksperymentu z jeszcze większym plikiem (około 1 GB) przyniosła znaczące spowolnienie po około 35-40 sekundach (wydaje się).

+0

Widzę to samo z prostą pętlą i = i + 1, drukującą komunikat co 1 milion iteracji. Spowolnienie rozpoczyna się po około 20 sekundach w przeglądarce Chrome i 12 sekundach w Firefoksie. Co to jest? –

Odpowiedz

12

Tyler Ault suggested one possibility on Google+ który okazał się bardzo pomocny.

Spekulował, że użycie FileReaderSync w wątku roboczym (zamiast zwykłego asynchronicznego FileReader) nie zapewniało możliwości wyrzucenia śmieci.

Zmiana wątku roboczego do korzystania FileReader asynchronicznie (który intuicyjnie wydaje się krokiem wstecz wydajności ) przyspieszył proces powrotem do zaledwie 37 sekund, dokładnie tam, gdzie bym się spodziewał, że będzie.

nie słyszałem z powrotem od Tyler jeszcze i nie jestem do końca pewien, czy rozumiem dlaczego zbieranie śmieci będzie winowajcą, ale coś o FileReaderSync był drastycznie spowalnia kod.

+0

Tak więc mam ten sam problem, ale moje odśmiecanie nie dzieje się z powodu obiecującego łańcucha, który nie pozwala odzyskać pamięci sterty. Używanie migawek Widzę, że fileReader zwalnia w prawo, gdy szyszka się wygładza, a następnie indeksuje, czekając, aż garbage collector zwolni więcej miejsca. – James

+0

Może usuwanie śmieci może się zdarzyć tylko po powrocie do pętli zdarzeń. –

2

Z jakiego sprzętu korzystasz? Być może masz problemy z buforowaniem pamięci podręcznej procesora. Na przykład, jeśli pamięć podręczna procesora wynosi 1 MB na rdzeń (tylko przykład) i zaczynasz próbować pracować z danymi ciągle zastępującymi pamięć podręczną (błędy w pamięci podręcznej), to będziesz cierpiał spowolnienia - jest to dość powszechne w systemach MT. Jest to powszechne również w transferze IO. Również te systemy mają również pewne narzuty OS w kontekście wątków. Więc jeśli pojawi się wiele wątków, możesz spędzać więcej czasu na zarządzaniu kontekstami niż wątek "robienie pracy". Jeszcze nie spojrzałem na twój kod, więc mogłem odejść - ale moje przypuszczenie dotyczy problemu z pamięcią tylko z powodu tego, co robi twoja aplikacja. :)

Oh. Jak naprawić. Spróbuj wykonać bloki wykonywania małych pojedynczych fragmentów pasujących do sprzętu. Zminimalizuj ilość używanych wątków naraz - staraj się utrzymać 2-3 razy więcej rdzeni w sprzęcie (to naprawdę zależy od tego, jaki masz hw). Nadzieja, która pomaga.

+0

Dzięki za te pomysły. Dodałem specyfikacje systemowe do mojego pytania. Zmniejszenie wielkości porcji jest interesującym pomysłem; Próbowałem go z porcjami 2 MB zamiast 10 MB i nadal zauważałem znaczny spadek prędkości dla tych ostatnich milionów wierszy (ponownie około 30 sekund). I zawsze działa tylko jeden pracownik WWW (również wyjaśniony w moim pytaniu). Wygląda więc na to, że niestety musimy znaleźć wyjaśnienie. – Matt

Powiązane problemy