Oprócz punktów wymienionych w innych odpowiedziach (trudno udowodnić, że operacje są niezależne, a programiści myślą poważnie), należy wziąć pod uwagę trzeci czynnik: koszt równoległości.
Prawda jest taka, że równoległość nici wiąże się z bardzo dużymi kosztami:
Tworzenie wątków jest bardzo kosztowne: dla jądra rozpoczęcie wątku jest prawie takie samo jak rozpoczęcie procesu. Nie jestem pewien co do dokładnych kosztów, ale uważam, że jest to rzędu dziesięciu mikrosekund.
Komunikacja wątków za pośrednictwem muteksów jest droga: zazwyczaj wymaga to wywołania systemowego z każdej strony, prawdopodobnie uśpienia wątku i wznowienia go, co powoduje opóźnienia, a także chłodzenie pamięci podręcznej i opróżnianie TLB. Średnio pobranie i wydanie muteksu kosztuje około jednej mikrosekundy.
Jak na razie dobrze. Dlaczego jest to problem z ukrytą równoległością? Ponieważ niejawna równoległość jest najłatwiejsza do udowodnienia w małych skalach. Jedną rzeczą jest udowodnienie, że dwie iteracje prostej pętli są od siebie niezależne, zupełnie inną rzeczą jest udowodnienie, że drukowanie czegoś stdout
i wysyłanie zapytania do bazy danych są od siebie niezależne i mogą być wykonywane równolegle ( proces bazy danych może być po drugiej stronie potoku!).
Oznacza to, że domniemana równoległość, którą program komputerowy może udowodnić, jest prawdopodobnie niewykonalna, ponieważ koszty równoległości są większe niż przewaga przetwarzania równoległego. Z drugiej strony, równoległość na dużą skalę, która może naprawdę przyspieszyć aplikację, nie jest możliwa do udowodnienia dla kompilatora. Pomyśl tylko, ile pracy może wykonać procesor w ciągu mikrosekundy. Teraz, jeśli równoległość ma być szybsza niż program szeregowy, program równoległy musi być w stanie utrzymać wszystkie procesory zajęte przez kilka mikrosekund między dwoma wywołaniami mutex. Wymaga to naprawdę gruboziarnistej równoległości, co jest prawie niemożliwe do udowodnienia automatycznie.
Wreszcie, żadna reguła bez wyjątku: Wykorzystanie niejawnej równoległości działa, gdy nie są zaangażowane żadne wątki, co ma miejsce w przypadku wektoryzacji kodu (przy użyciu zestawów instrukcji SIMD, takich jak AVX, Altivec itp.). To rzeczywiście działa najlepiej w przypadku paralelizmu na małą skalę, który jest stosunkowo łatwy do udowodnienia.