Rozczarowująca wydajność z Parallel.For
Próbuję przyspieszyć czas obliczeń za pomocąParallel.For
. Mam procesor Intel Core i7 Q840 z 8 rdzeniami, ale udaje mi się uzyskać tylko 4-krotny współczynnik wydajności w porównaniu z sekwencyjnymfor
pętla. Czy to tak dobrze, jak tylko możeParallel.For
lub czy wywołanie metody można precyzyjnie dostosować, aby zwiększyć wydajność?
Oto mój kod testowy, sekwencyjny:
var loops = 200;
var perloop = 10000000;
var sum = 0.0;
for (var k = 0; k < loops; ++k)
{
var sumk = 0.0;
for (var i = 0; i < perloop; ++i) sumk += (1.0 / i) * i;
sum += sumk;
}
i równolegle:
sum = 0.0;
Parallel.For(0, loops,
k =>
{
var sumk = 0.0;
for (var i = 0; i < perloop; ++i) sumk += (1.0 / i) * i;
sum += sumk;
});
Pętla, która jest równoległa, polega na obliczaniu zmiennej „globalnie”,sum
, ale powinno to stanowić jedynie niewielką, niewielką część całkowitego czasu w równoległej pętli.
W wersji Release (ustawiona flaga „optymalizuj kod”) sekwencyjnyfor
pętla zajmuje 33,7 s na moim komputerze, podczas gdyParallel.For
pętla trwa 8,4 s, współczynnik wydajności wynosi tylko 4,0.
W Menedżerze zadań widzę, że wykorzystanie procesora wynosi 10-11% podczas obliczeń sekwencyjnych, podczas gdy podczas obliczeń równoległych wynosi tylko 70%. Próbowałem wyraźnie ustawić
ParallelOptions.MaxDegreesOfParallelism = Environment.ProcessorCount
ale bez skutku. Nie jest dla mnie jasne, dlaczego nie cała moc procesora jest przypisana dorównolegle obliczenie?
Zauważyłem, że podobne pytanie zostało podniesione w sprawie SOprzed, z jeszcze bardziej rozczarowującym wynikiem. Jednak to pytanie wymagało również niższej równoległości w bibliotece innej firmy. Moją podstawową troską jest równoległość podstawowych operacji w bibliotekach podstawowych.
AKTUALIZACJA
W niektórych komentarzach wskazano mi, że procesor, którego używam, ma tylko 4 rdzenie fizyczne, co jest widoczne dla systemu jako 8 rdzeni, jeśli włączona jest hiperwątkowość. W tym celu wyłączyłem hiperwątkowość i ponownie przetestowałem.
Z hiperwątkowościąwyłączone, moje obliczenia są terazszybciej, zarówno równoległe, jak i (to, co myślałem) sekwencyjnefor
pętla. Wykorzystanie procesora podczasfor
pętla wynosi do ok. 45% (!!!) i 100% podczasParallel.For
pętla.
Czas obliczeń dlafor
pętla 15,6 s (ponad dwukrotnie szybciej niż w przypadku hiperwątkowości)włączone) i 6,2 s dlaParallel.For
(25% lepsze niż w przypadku hiperwątkowościwłączone). Współczynnik wydajności zParallel.For
jest teraz tylko2.5, działa na 4 rzeczywistych rdzeniach.
Tak więc współczynnik wydajności jest nadal znacznie niższy niż oczekiwano, pomimo wyłączenia hiperwątkowości. Z drugiej strony jest intrygujące, że wykorzystanie procesora jest tak wysokie podczasfor
pętla? Czy w tej pętli może istnieć jakaś wewnętrzna równoległość?