- •1. Введение
- •2. Многопоточное программирование
- •3.1. Example1: работа с памятью
- •3.1.1. Производительность
- •3.1.2. Масштабируемость
- •3.1.3. Масштабируемость Hyper-Threading архитектур
- •3.2. Example2.Exe: работа с файлами
- •4. Многопоточные программы
- •4.1. Mtftext.Exe: учебный пример
- •4.2. Mtcksrc.Exe: проверка исходного кода
- •If (tout.Size()) file(mp, fd::out).Write(tout);
- •4.3. Mtdel.Exe: удаление файлов
- •Вывод итоговой статистики, т.Е. Общего количества удаленных файлов и их совокупного размера.
- •Сообщение о возникших ошибках, как последнее сообщение программы.
- •4.4. Mtcnvsrc.Exe: конвертация исходного кода
- •4.5. Mtdirdiff.Exe: сравнение директорий
- •Mem_pool ownmp;
- •5. Библиотека derslib
- •6. Заключение
3.1.1. Производительность
Усредненные результаты запусков (на разных компьютерах и системах) представлены в таблице:
1 CPU |
||||||||
numThr |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
std |
13.913 |
28.01 |
43.255 |
62.984 |
85.696 |
107.184 |
128.758 |
155.022 |
ders |
0.507 |
1.011 |
1.512 |
2.022 |
2.533 |
3.054 |
3.562 |
4.068 |
std/ders |
27.4 |
27.7 |
28.6 |
31.1 |
33.8 |
35.1 |
36.1 |
38.1 |
1 CPU, Hyper-Threading |
||||||||
numThr |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
std |
60.057 |
135.573 |
211.156 |
278.135 |
350.625 |
415.437 |
489.187 |
558.109 |
ders |
1.182 |
3.322 |
4.968 |
6.635 |
8.242 |
10.020 |
11.661 |
13.239 |
std/ders |
50.8 |
40.8 |
42.5 |
41.9 |
42.5 |
41.5 |
42.0 |
42.1 |
2 CPU, SMP |
||||||||
numThr |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
std |
20.385 |
129.032 |
206.760 |
256.699 |
333.670 |
384.449 |
455.674 |
519.002 |
ders |
0.396 |
0.406 |
0.609 |
0.812 |
1.014 |
1.218 |
1.455 |
1.614 |
std/ders |
51.5 |
317.8 |
339.5 |
316.1 |
329.1 |
315.6 |
313.2 |
321.6 |
2 CPU, Hyper-Threading |
||||||||
numThr |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
std |
3.286 |
24.679 |
37.496 |
52.798 |
66.961 |
80.461 |
95.084 |
109.309 |
ders |
0.580 |
0.582 |
1.468 |
1.472 |
1.900 |
2.257 |
2.628 |
2.953 |
std/ders |
5.7 |
42.4 |
25.5 |
35.9 |
35.2 |
35.6 |
36.2 |
37.0 |
Время работы указано в секундах, а в строке std/ders приведено отношение времени работы функций -- именно те данные, которые нас и интересуют. Следующая ниже диаграмма показывает их в более наглядной форме:
Удивительно, но факт: относительный выигрыш 2 CPU, SMP компьютера настолько велик, что даже имеет смысл привести ту же самую диаграмму без его участия:
Проведем краткий анализ:
Функция start_ders, использующая аллокатор на основе mem_pool работает в десятки и даже сотни (!!!) раз быстрее. Так что "повсеместное мелькание" mem_pool& является, мягко говоря, оправданным. И даже более того! Учитывая ТАКУЮ разницу эффективности, вопрос должен ставиться совершенно иначе:
Производительность стандартных STL контейнеров в MT приложениях может быть катастрофически неприемлемой!
Относительное время работы существенным образом варьируется, пока количество рабочих потоков не достигнет количества доступных (логических) процессоров:
1 CPU. В силу того, что потокам доступен всего лишь один процессор, никаких вариаций не может быть видно: отношение сразу же начинает нарастать и нарастает практически линейно на протяжении всего графика (т.е. по мере увеличения количества рабочих потоков).
1 CPU, Hyper-Threading. В этом случае система пытается вести себя так, как будто приложению доступно два независимых "логических" процессора, а не один (компетентные источники утверждают, что максимум того, что мы можем получить с точки зрения производительности это примерно 1.3 независимых процессора, не более). Как можно видеть, наибольший относительный выигрыш в 51 раз получается при одном рабочем потоке. Затем он падает до 41 раза на двух потоках и начиная с трех потоков стабилизируется около 42-х.
2 CPU, SMP. А здесь мы уже имеем два полноценных независимых процессора. Даже на единственном рабочем потоке относительный выигрыш в 51.5 раз уже превосходит результаты всех остальных компьютеров, но на двух и более потоках (с появлением реальной синхронизации и неизбежно вызываемых ею задержек) выигрыш скачкообразно увеличивается до 318 (!!!) раз и далее стабилизируется около этого значения. Данный случай является безусловным лидером нашего хитпарада!
2 CPU, Hyper-Threading. В отличии от второго случая с единственным HT процессором, два HT процессора на одном рабочем потоке показывают минимальный выигрыш -- всего 6 раз. Но аналогично третьему варианту, на двух потоках выигрыш скачкообразно (и примерно в те же 6-7 раз) увеличивается до 42, но на трех припадает, до 26. С четырех и далее потоков прослеживается более-менее стабильный результат в 36 раз, возможно увеличивающийся по мере роста количества рабочих потоков.
По исчерпании всех свободных процессоров ни о каком параллелизме уже не может быть речи, что все четыре рассмотренных графика в полной мере нам и продемонстрировали.