Pytanie Wysoce równoległy program F # wykazuje słabe wykorzystanie procesora


Jedną z obietnic czystego programowania funkcjonalnego jest to, że dobrze się układa. Testuję to oświadczenie, używając aplikacji F # z miernymi wynikami. Mój program uruchamia dużą liczbę wyszukiwań MiniMax równolegle za pośrednictwem Array.Parallel. Algorytm MiniMax to czysty kod funkcjonalny - brak współdzielonego stanu, brak blokad, ale wysoce rekursywny z wieloma wartościami tworzonymi i niszczonymi podczas przeszukiwania drzewa. W ogóle nie ma I / O - wszystko jest w pamięci. Każde wyszukiwanie MiniMax zajmuje 5-60 sekund, a ja pracuję z około 100 równolegle na szybkim pudełku z 8 rdzeniami procesora. Niestety, szczyt wykorzystania procesora wynosi około 65% i zwykle mieści się w zakresie 45-60%.

Profilowałem swoją aplikację za pomocą Wizualizatora Współbieżności Visual Studio i stwierdziłem, że jest blokowane około 40% czasu. Wszystkie wywołania blokujące wydają się być w zbieraczu pamięci .NET lub innych procedurach zarządzania pamięcią .NET. Czy istnieje sposób na zoptymalizowanie tego zachowania bez przepisywania całego programu w języku niższego poziomu, takim jak C ++? Wydaje się oczywiste, że problem polega na tym, że tworzę i niszczę zbyt wiele obiektów, ale trudno tego uniknąć w idiomatycznym kodzie F #. Być może brakuje mi innej przyczyny problemów z synchronizacją?

Dzięki.

Aktualizacja: Wprowadziłem dwie zmiany: Wyłączono funkcję hyperthreading i użyłem gcServer w moim pliku konfiguracyjnym. To skróciło czas wykonania mojego testu z 32 do 13 sekund! Wykorzystanie procesora jest również znacznie wyższe. Dziękujemy wszystkim, którzy zgłosili sugestie.


11
2017-08-26 17:13


pochodzenie


Jeśli tworzysz wiele instancji, równoległość może być ograniczona przez usuwanie śmieci. W każdym razie musisz profilować aplikację, aby dowiedzieć się, jak spędza się czas. Bez danych, nikt się nie domyśla, dlaczego widzisz to zachowanie. - Brian Rasmussen
Profilowałem aplikację i większość czasu spędzam w algorytmie MiniMax, tworząc węzły potomne, tak jak się spodziewałem. Byłbym szczęśliwy mogąc udostępniać dane, ale nie jestem pewien, jak to zrobić bez publikowania całej aplikacji. - brianberns
Zanim poświęcisz temu zbyt dużo czasu, upewnij się, że problem nie jest prosty. Czy używasz maszyny z włączonym hyper-threading? Jeśli tak, system operacyjny prawdopodobnie zgłasza dwa razy więcej procesorów logicznych niż rdzeni fizycznych, a to może przekrzywić raportowanie użycia procesora ("wirtualne" procesory mają stosunkowo niskie wykorzystanie). - Mike Strobel
100 na 8 cpu wydaje się dużo. Spróbuj 20. - paparazzo
@MikeStrobel: Dzięki, wygląda na to, że włączona jest funkcja hyperthreading. Wyłączę to i zobaczę, jak to wpływa na wyniki. - brianberns


Odpowiedzi:


Powinieneś skonfigurować swoją aplikację tak, aby korzystała z funkcji czyszczenia pamięci serwera. Zobacz dokumentację gcServer element dla szczegółów. Domyślny garbage collector po prostu nie pozwala na przydzielanie ciężkich programów do skalowania do wielu rdzeni.


9
2017-08-26 18:02