powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
35 сообщений из 35, показаны все 2 страниц
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36038886
unicornmirage
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здравствуйте.
Позвольте задать такой вопрос:
Предположим у меня есть прочитанный блок 100Мб в виде массива байт byte[1024 * 1024 * 100]. И есть алгоритм быстрой сортировки (quickSort) - который выполняет сортировку 100Мб за N-секунд.
Стоит ли разбивать этот массив на части и сортировать по более мелким кускам (например по 16Кб - сортируем quickSort) а затем использовать сортировку слиянием? Либо особого выигрыша здесь уже не получить, т.к. данные уже в памяти.
С другой стороны - на самом деле у меня в памяти 10 блоков по 100Мб. Изначально я планировал создавать 10 потоков, каждый поток будет сортировать свой блок 100Мб. Это позволит эффективнее использовать процессоры. Так вот соль вопроса в том - надо ли дробить сортировку в каждом из блока?
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36039005
Partisan M
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
автор
Стоит ли разбивать этот массив на части и сортировать по более мелким кускам (например по 16Кб - сортируем quickSort) а затем использовать сортировку слиянием? Либо особого выигрыша здесь уже не получить, т.к. данные уже в памяти.



Если сортировать в одном потоке, то не будет вообще никакого выигрыша. Однако если распараллелить сортировку частей, а потом сливать, то ускорение будет (если компьютер с многоядерным процессором или хотя бы процессор с hyperthreading). Однако думаю части должны быть крупными, иначе потребуется много слияний. Например, если процессор 2-ядерный, то разбиваем на 2 части и делаем 1 слияние. Даёт хороший прирост скорости, но с большой оговоркой - если время сортировки частей примерно одинаково, а оно зависит от распределения данных внутри части (это я проводил эксперименты). Для борьбы с этим можно поделить массив на большее число частей, но понадобится больше слияний, то есть их тоже желательно распараллелить по потокам. Порядок слияний влияет на их общую трудоёмкость.
Вообще-то уже есть функции сортировки, распараллеленные внутри себя по этому способу - в библиотеке GCC 4.4 есть распараллеленные варианты функций std::sort, std::stable_sort и др. для C++, да и не только в GCC.
Кстати, сейчас в стандартный библиотеках компиляторов обычно применяется алгоритм не QuickSort, а IntroSort, но для него справедливы те же выводы.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36041046
aleks2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
unicornmirage,

Алгоритм QuickSort - естественным образом распараллеливается. Если вы этого не понимаете - хреновато вы изучили алгоритм.

Сортировка слиянием выигрывает, если НЕТ возможности произвольного доступа к областям памяти - т.е. на файлах.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36041114
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сортировка слиянием имеет смысл только при очень больших объёмах, когда не хватает оперативки. В остальных случаях используйте quick sort или "специализированные" методы, которые заточены под статистику ваших данных.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36041155
Фотография Gluk (Kazan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aleks2
Алгоритм QuickSort - естественным образом распараллеливается. Если вы этого не понимаете - хреновато вы изучили алгоритм.


хреново он параллелится, между нами девочками
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36041157
Фотография Gluk (Kazan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gluk (Kazan)aleks2
Алгоритм QuickSort - естественным образом распараллеливается. Если вы этого не понимаете - хреновато вы изучили алгоритм.


хреново он параллелится, между нами девочками

А вот побить на большие куски, которые сортируются в памяти параллельно, а потом дружненько сливаются - один в один по кнышке
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36041175
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Может быть он имеет в виду, неравномерность деления медианой? В этом случае один из вычислительных потоков будет "ожидать" другой.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36041205
уральский
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
maytonМожет быть он имеет в виду, неравномерность деления медианой? В этом случае один из вычислительных потоков будет "ожидать" другой.
Полагаю, имелась ввиду возможность сортировать две (а потом четыре и восемь и т.д. сколько процессоров есть) части массива параллельно после разбиения его медианой.
Это, как заметил Gluk (Kazan), хреновое распараллеливание :)
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36042387
Partisan M
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gluk (Kazan)хреново он параллелится, между нами девочками

Вообще-то я уже ответил. Можно конечно уточнять. Но раз другие не уточняют, то сам это делаю.

Алоритм QuickSort распараллеливается хорошо, хотя бы потому,что его формулировка рекурсивная. Но самостоятельная эффективная реализация алгоритма нетривиальна, и нет самысла ею заниматься, можно применить функции сортировки из стандартных библиотек - причём есть как распараллеленные внутри (тогда самому ничего делать не надо), либо взять обычную не распалаллеленную версию и распараллелить самостоятельно. Для этого массив поделить на части, сортировать их параллельно и сливать. При этом возникают проблемы оптимизации, которые я уже описал.

Также, как я написал, в нынешних стандарных библиотеках вместо QuickSort обычно используется IntroSort - эта замена сделана для борьбы со "сложным случаем" сортировки в QuickSort, когда её трудоёмкость достигает O(N*N), хотя в среднем она O (N*LOG N). Таким образом, для самостоятельного программирования QuickSort надо разбираться в предмете, но особого смыла оно не имеет. (Для примера, в MS Visual Studio 2008, в библиотеке C++ функции qsort, std::sort и std::stable_sort все реализуют алгоритм IntroSort, ими и пользоваться. Сливать части - функцией std::merge - но это только в C++).

На сколько частей разбивать.
Независимо от числа частей, в среднем трудоёмкость сортировки составит O(N*LOG N). Но это не значит, что число частей не имеет значения. Потому что надо учесть факторы:
- число частей при распараллеливании должно быть не меньше числа потоков выполнения (зависит от числа процессоров, ядер и наличия hyperthreading). Наапример, 2 ядра без hyperthreading - делаем не менее 2 потоков.
- но если сделать ровно 2 (как в описанном случае), а распределение значений не случайное, то один поток может закончить работу быстрее, чем второй, и простивать. Поэтому сделать больше - скажем, десяток. Одновременно пусть работают 2 и если один отсортирует свой отрезок, пусть начинает сортировать ещё не сортированный или сливать уже отсортированные. Очень много отрезков делать ни к чему, т.к. оптимизация от равномерной загрузки ядер будет уже небольшая.
- Порядок слияния отсортированных частей влияет на трудоёмкость слияния.
- Можно попытаться сделать оптимизацию типа "суперлинейный рост скорости". А именно, обычно рост скорости от распараллеливания - медленнее роста числа процессоров (закон Амдаля), но иногда бывает и более быстрым, чем рост числа процессоров (ядер). Это происходит, когда сортируемая часть массива полностью помещается в кеш, относящийся к процееору (ядру). То есть, ориентировочно сотни килобайт. Более мелкие куски массива уже нет смысла делать. Подробнее о "суперлинейном росте скорости" можно ппочитать в документации по организации многопоточной обработки OpenMP, но он - не свойство OpenMP, а свойство архитектуры компьютера. Библиотека OpenMP вообще удобна для распараллеливания сортировки, хотя совершенно необязательна.

Вот, написал сколько хватило терпения. Напоследок привожу фрагменты моёй программы сортировки с распараллеливанием на 2 потока функции std::stable_sort (которую легко заменить на любую другую), применяется библиотека OpenMP. Полные примеры для Visual C++ и GCC я уже привёл на форуме ixbt. Пример примитивный - в явном виде задаются 2 потока, для демонстрации идеи. Библиотека OpenMP позволяет легко задавать число потоков динамически (что и следовало бы сделать в практической программе). Но демонстрация возможностей OpenMP не являлась задачей.

Пример. Определение массива (можно заменить на любое другое):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
//Структура: элемент сортируемого массива. В тесте можно было 
//обойтись и без неё. Но если добавить ещё поля, то можно будет сравнивать
//элементы по нескольким признакам, модифицировав последующий оператор '<'.
struct Item {
	long value;
};

//оператор сравнения элементов сортируемого массива для применения в std::sort:
bool operator < (const struct Item& item1, const struct Item& item2) 
{   //возвращает "истину", если порядок правильный:
	return (item1.value <= item2.value);
}

namespace 
{
	struct ItemDefaultCompare 
	{
		bool operator () (const struct Item& item1, const struct Item& item2) const
		{
			return (item1.value <= item2.value);
		}
	};
}

//сортируемый массив:
struct Item items [N];

Сортирующий фрагмент кода:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
        //Делаем 2 потока:
	#pragma omp parallel shared (items, halfN) num_threads (2)
	{
		#pragma omp sections 
		{   //параллельно выполняемые участки программы
			#pragma omp section
			{
				std::stable_sort (items, items + halfN, ItemDefaultCompare ());//первая половина массива
			}
			#pragma omp section
			{
				std::stable_sort (items + halfN, items + N, ItemDefaultCompare ());//вторая половина массива
			}
		}
	}
	//конец многопоточности

        //сливаем:
	std::inplace_merge (items, items + halfN, items + N);
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36042399
уральский
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Partisan MАлоритм QuickSort распараллеливается хорошо, хотя бы потому,что его формулировка рекурсивная.
С каких это пор рекурсивность стала признаком хорошей распараллеливаемости?
Он распараллеливается хоть как-то (плохенько) только благодаря тому, что рекурсивный вызов - двойной, после разбиения медианой получившиеся две части можно сортировать независимо. Рекурсия тут ни при чем совершенно.

Partisan MТакже, как я написал, в нынешних стандарных библиотеках вместо QuickSort обычно используется IntroSort - эта замена сделана для борьбы со "сложным случаем" сортировки в QuickSort, когда её трудоёмкость достигает O(N*N), хотя в среднем она O (N*LOG N). Таким образом, для самостоятельного программирования QuickSort надо разбираться в предмете, но особого смыла оно не имеет. (Для примера, в MS Visual Studio 2008, в библиотеке C++ функции qsort, std::sort и std::stable_sort все реализуют алгоритм IntroSort, ими и пользоваться. Сливать части - функцией std::merge - но это только в C++).
Для примера в .NET - quicksort, причем с выбором pivot по среднему индексу xD
Вот некоторые люди напарываются)))

Partisan MНезависимо от числа частей, в среднем трудоёмкость сортировки составит O(N*LOG N).
ё, да это и ежу ясно, что распараллеивание не влияет на сложность (характер роста), алгоритм-то тот же самый, но оно влияет на коэффициент с этом самом "О-большое", n*logn и n*logn/16 - разные вещи таки, хотя и то и другое O(n*logn) :)
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36042529
RT183
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
чё то бред какой-то с этим "распараллеливанием"
Параллелются солдаты прочесывающие лес в поисках чего-то
но не сортировка
Сортировка -- это не поиск чего-то, это процесс, его надо
пройти до конца.
Какая хрен разница сколько у тебя процессоров, 1, 2, 4, 256
Технически могут быть разные отклонения, туда-сюда, но очень незначительные.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36042530
RT183
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ну может быть
sort , stable_sort
где-то там и скрещиваются и интеллектуизируются
А может и sort() -- это совсем не хоаровский qsort.
Мне это до лампочки.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36042557
Partisan M
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На дурацкие комментарии отвечать не буду. Нет ничего настолько простого, чтобы не нашёлся кто-нибудь, неспособный это понять. В общем, я описал распараллеливание сортировки довольно подробно. Может, кому-нибудь поможет. А если кому не поможет, то пусть это будет его проблемой.

Да, по OpenMP можно найти книжки на английском языке и много статей.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36042560
RT183
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Partisan MНа дурацкие комментарии отвечать не буду. Нет ничего настолько простого, чтобы не нашёлся кто-нибудь, неспособный это понять. В общем, я описал распараллеливание сортировки довольно подробно. Может, кому-нибудь поможет. А если кому не поможет, то пусть это будет его проблемой.

Да, по OpenMP можно найти книжки на английском языке и много статей.
ну зачем это называть распараллеливанием? Это совсем из другой оперы.
И твою идею из первого поста я прекрасно понял: но тут надо проверять, тут хер знает сколько нюансов
На одних данных может быть так, на других по-другому
Ты же сам не собираешься случай:
разобьем всё на пары (сделаем своп), отсортируем мерджем потом
Да это глупо всё и бесполезно и непонятно куда ты это хочешь прилепить и зачем
И 100 мб -- это копейки
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36042562
RT183
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Забудь ваще это слово -- "распараллеливание".
Это ламерское слово. У людей есть только одна ось Времени.
У нас нет двух осей Времени и не будет, хоть ты тресни.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36042658
уральский
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
RT183Забудь ваще это слово -- "распараллеливание".
Это ламерское слово. У людей есть только одна ось Времени.
У нас нет двух осей Времени и не будет, хоть ты тресни.
Глупость какая. У нас есть много вычислительных элементов и одна задача, вот что важно.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36042732
Фотография Gluk (Kazan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Partisan MGluk (Kazan)хреново он параллелится, между нами девочками

Вообще-то я уже ответил. Можно конечно уточнять. Но раз другие не уточняют, то сам это делаю.

Алоритм QuickSort распараллеливается хорошо

... Бла Бла Бла не относящееся к проблеме распараллеливания QuickSort ...



Вообще то тут об этом уже сказали, но я тоже скажу :)
Безусловно существуют алгоритмы сортировки, специально разработанные для того, чтобы их параллелить, но именно QuickSort к ним определенно не относится, какой бы он рекурсивный там не был

Дело в том, что кусочки массива, которые он отдает на сортировку своим рекурсивным вызовам оччень разные по размеру, в некоторых реализациях они сильно разные даже на одном уровне рекурсии, а для распараллеливания это ... несколько неудобно. И вообще параллелить дерево рекурсивных вызовов ...

В общем вы понимаете (с)
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36042767
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gluk (Kazan)
Дело в том, что кусочки массива, которые он отдает на сортировку своим рекурсивным вызовам оччень разные по размеру, в некоторых реализациях они сильно разные даже на одном уровне рекурсии, а для распараллеливания это ... несколько неудобно. И вообще параллелить дерево рекурсивных вызовов ...

Думаю, что распараллелить всё-таки можно, но насколько будет это эффективно? Если прирост будет порядка 10-15% то не стоит связываться. В любом случае, нам нужны цифры.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36042802
Фотография Gluk (Kazan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonGluk (Kazan)
Дело в том, что кусочки массива, которые он отдает на сортировку своим рекурсивным вызовам оччень разные по размеру, в некоторых реализациях они сильно разные даже на одном уровне рекурсии, а для распараллеливания это ... несколько неудобно. И вообще параллелить дерево рекурсивных вызовов ...

Думаю, что распараллелить всё-таки можно, но насколько будет это эффективно? Если прирост будет порядка 10-15% то не стоит связываться. В любом случае, нам нужны цифры.

Можно конечно (раздел 1.5) только не лучшая эта задача для распараллеливания. И QuickSort на больших объемах не лучший выбор (а на небольших нефих его параллелить). При том что лучшее решение лежит на поверхности, говорить о том, что QuickSort паралелится моветон :)
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36043064
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я читал Грегори Эндрюса, вот только не помню, чтобы он там описывал сортирующие алгоритмы.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36043174
Фотография Gluk (Kazan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonЯ читал Грегори Эндрюса, вот только не помню, чтобы он там описывал сортирующие алгоритмы.

Упоминается QuickSort, но описывается адаптивная квадратура.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36045074
aleks2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gluk (Kazan)Partisan MGluk (Kazan)хреново он параллелится, между нами девочками

Вообще-то я уже ответил. Можно конечно уточнять. Но раз другие не уточняют, то сам это делаю.

Алоритм QuickSort распараллеливается хорошо

... Бла Бла Бла не относящееся к проблеме распараллеливания QuickSort ...



Вообще то тут об этом уже сказали, но я тоже скажу :)
Безусловно существуют алгоритмы сортировки, специально разработанные для того, чтобы их параллелить, но именно QuickSort к ним определенно не относится, какой бы он рекурсивный там не был

Дело в том, что кусочки массива, которые он отдает на сортировку своим рекурсивным вызовам оччень разные по размеру, в некоторых реализациях они сильно разные даже на одном уровне рекурсии, а для распараллеливания это ... несколько неудобно. И вообще параллелить дерево рекурсивных вызовов ...

В общем вы понимаете (с)

Если вы не умеете параллелить, это еще не означает что "оно плохо параллелится". Признаком ХОРОШЕЙ параллельности является исключительно наличие операций НЕЗАВИСИМЫХ от других. QSort порождает такие операции - деление медианой массива. Я, канешно, понимаю что НЕРЕКУРСИВНАЯ реализация QSort для вас загадка, но поверьте: рекурсия НЕ обязательна. В этом случае порождается очередь запросов на сортировку которую можно обрабатывать во столько потоков, сколько у вас есть.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36045287
Фотография Gluk (Kazan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aleks2
Если вы не умеете параллелить, это еще не означает что "оно плохо параллелится". Признаком ХОРОШЕЙ параллельности является исключительно наличие операций НЕЗАВИСИМЫХ от других. QSort порождает такие операции - деление медианой массива. Я, канешно, понимаю что НЕРЕКУРСИВНАЯ реализация QSort для вас загадка, но поверьте: рекурсия НЕ обязательна. В этом случае порождается очередь запросов на сортировку которую можно обрабатывать во столько потоков, сколько у вас есть.

Друг мой, рекурсия для меня не загадка (также как и то что любой рекурсивный алгоритм можно перевести в итеративную форму), но суть не в этом. Для того, чтобы задачка ХОРОШО (а не просто абы как) параллелилось, желательно чтобы параллельные процессы выполняли по возможности одинаковый объем работ, в противном случае, издержки на управление, синхронизацию и т.п. убьют на корню все бенефиты, которые даст нам распараллеливание. В случае QuickSort это не так, размеры сортируемых регионов уменьшаются на каждом уровне рекурсии, более того, поскольку медиану искать весьма накладно (и это тоже дополнительные издержки на реализацию хорошей многопоточности), в большинстве случаев в качестве "медианы" берется первый попавшийся элемент, и как следствие половинки становятся очень неодинаковы

В общем меня несколько утомила эта дискуссия и продолжение ее я предлагаю вести в следующей форме:

1. Вы предоставляете свою версию параллельного QuickSort (ну скажем на 8 процессоров на 100000 элементов)
2. Я реализую кондовый однопоточный рекурсивный QuickSort, ага
3. Сравниваем производительность, на моем железе
4. Я кричу "Шайтан" и рву на себе волосы, поскольку ваш вариант работает быстрее в N раз

так пойдет ?
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36045300
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gluk (Kazan)...
+1

Я тоже хотел-бы увидеть сравнительный тест. Только 8 процессов - это слишком. Сделать хотя-бы 2.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36045351
Фотография Gluk (Kazan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonGluk (Kazan)...
+1

Я тоже хотел-бы увидеть сравнительный тест. Только 8 процессов - это слишком. Сделать хотя-бы 2.

На 2 вообще понту нет (особенно ядрах)
256 процов не обещаю, но уж 8 и память чтобы лям int-ов влезло можно пошукать
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36052394
Partisan M
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gluk (Kazan)На 2 вообще понту нет (особенно ядрах)
Есть понт даже и на двух. Далее привожу результаты тестов.

maytonДумаю, что распараллелить всё-таки можно, но насколько будет это эффективно? Если прирост будет порядка 10-15% то не стоит связываться. В любом случае, нам нужны цифры.

Я на это тоже косвенно ответил, сославшись на свой программный пример в форуме ixbt (где я Partisan, здесь ещё добавил M потому что забыл свой пароль). Там я привёл полные исходные коды своего программного примера распараллеливания сортировки на 2 потока (потому что был 2-ядерный процессор Athlon X2 5600+, модель с кешем 2x1МБ), и ускорение получалось почти в 2 раза. Привёл варианты программы для Linux и Windows, причём ввиду переносимости библиотеки OpenMP код, нужный для распараллеливания, оказался одинаковым. Те же программы на 1-ядерном процессоре, но с hyperthreading, дали прирост в 30%. Сортировался массив равонмерно распределённых случайных чисел в несколько мегабайт. Диапазон значений чисел был большим - а то при наличии большого числа повторряющихся значений у многих алгоритмов работа ускоряется (за счёт меньшего числа перестановок элементов), что искажает результат.

Ещё сослался на закон Амдаля (Amdahl law), говорящий, что при распараллеливании рост скорости несколько меньше, чем рост числа процессоров (поскольку часть вычислений остаётся нераспараллелленной). Но для сортировки результат и должен быть хорошим.

Сейчас приведу модифицированный вариант моей тестовой программы для Linux, в котором дополнительно испытываются распараллеленные версии функций библиотеки STL (parallel mode STL), появившиеся в GCC 4.4 (который входит в дистрибутив Fedora 11). В примере использовалась такая функция __gnu::parallel::stable_sort.

Кратко:
- для массива в 100 МБ (25 миллионов целых чисел) моё распаларелливание для std::stable_sort дало прирост всего 1,5 раза. Надо разбираться, почему так мало. (Предупреждение: при подозрительно маленьком приросте надо изучить, нет ли явления "ложного распараллеливания". Но не уверен, что это оно). При уменьшении размера массива результат улучшался.
- внутренне распараллеленный вариант этой функции __gcc_parallel::stable_sort был на 1-8% быстрее, чем мой, что непринципиально (какая-то мелкая оптимизация).
- чтоб распараллеливаение в __gnu_parallel::stable_sort и подобных работало, надо добавить опеределение #define _GLIBCXX_PARALLEL 1 в программу или ключ
строки компиляции -D_GLIBCXX_PARALLEL (согласно документации. Оказалось, что при этом std::sort ускоряется в той же степени, то есть рассматривается как __gnu_parallel::stable_sort,
о чём в документации по "параллельному режиму STL" не сказано (но она скудная).

Результаты (сортировка 25 миллионов целых чисел, в секундах, среднее из 10 испытаний). Процессор Athlon X2 6000+ модель с кешем 2x1МБ:
1) c использованием -D_GLIBCXX_PARALLEL
- std::stable_sort - 2,63
- моё распараллеливание std::stable_sort на 2 потока - 2,88
- __gnu_parallel::stable_sort - 2,65
Повторяю: std::sort тут втихомолку распараллелилось, сведясь к __gnu_parallel::stable_sort,
что видно из:
2) исключаем из строки компиляции ключ -D_GLIBCXX_PARALLEL
- std::stable_sort - 4,11
- моё распараллеливание sta_stable_sort - 2,67
- __gnu_parallel::stable_sort - 2,63

Вот текст программы. Командная строка компиляции приведена в нём. Ключ -march=... требуется для параллельного режима STL, так же как библиотека OpenMP. У кого старый GCC, может исключить из примера 3-й тест (с __gnu_parallel::stable_sort) и
строку #include <parallel/algorithm>
[src]
/**
* OMP_SORT_EX
*
* версия 1.4 добавлен тест функций __gnu_parallel::*
* Компиляция:
* g++ -fopenmp -O2 omp_sort_ex.cpp -o omp_sort_ex -lgomp
*
* Выполнение:
* ./omp_sort_ex [число циклов тестирования]
*
* версия 1.3
*
* - добавлено испытание параллельной версии
* функции сортировки (требуется GCC 4.4).
* - сообщения переведены на русский язык
* - название программы изменено с omp_sort на opm_sort_ex.
* Компиляция:
* g++ -fopenmp -O2 -march=native -D_GLIBCXX_PARALLEL omp_sort_ex.cpp -o omp_sort_ex -lgomp
*
* Проверено в Fedora 11, 64-битной.
*
* версия 1.2
*
* - добавлено выполнение в цикле
*
* версия 1.1
*
* - используется std::stable_sort вместо std::sort
*
* Демонстрация многопоточной сортировки.
* Требуется компилятор с поддержкой OpenMP (http://www.openmp.org),
* например GCC версии 4.2.1 и выше (для RedHat - от 4.1.1).
* Проверено в CentOS 5.0 386 с GCC 4.1.1.
*
* Компиляция:
* g++ -fopenmp -O2 omp_sort.cpp -o omp_sort -lgomp
*
* Здесь ключ -O2 (оптимизация) не обязателен, но значительно увеличивает скорость теста.
* Добавить другие необязательные ключи по вкусу.
* Ключ -lgomp обязателен только при использовании библиотеки libgomp,
* то есть, если в программе используются функции OpenMP,
* а не только директивы OpenMP (многопоточность можно создать одними директивами).
*
* Библиотека libgomp - в RedHat имеет свой RPM пакет.
* Искать libgomp надо в /usr/lib.
*
* Вызов:
* ./opm_sort [100]
* где необязательный параметр - число повторений
* (выполнение в цикле - чтобы проверить правильность
* общего показываемого времени вручную и для устреднения результатов,
* а то они сильно колеблются).
*
*/


#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <algorithm>
#include <parallel/algorithm>


#define VERSION_LABEL "v.1.4"
#define N 25000000L //размер сортируемого массива
#define RANGE 100000000 //диапазон изменения случ. чисел
#define TESTS 10 //количество циклов тестов



long values [N];//массив для сортировки
long randoms [N];//заполняем случайными числами один раз,а потом копируем в values

//Заполнить массив случайными числами от 0 до range-1.
//Не переносимо в Visual Studio, поскольку там RAND_MAX маленькое (32767),
//в то время как для GCC оно вполне приличное (2147483647):
void fillRandomArray (long* arr, int arrSize, int range)
{

srand (time (0));
for (int i = 0; i < arrSize; i ++)
{
arr [i] = (long) ((double)rand () / (double)RAND_MAX * range);
}
}

//Показать, какова упорядоченность массива. Вызывается до и после сортировки
void putOrderInfo (long* arr, int arrSize)
{ //сколько элементов:
int lesser = 0; //...меньше предыдущего
int equals = 0; //...равных предыдыдущему
int greather = 0; //...больше предыдущего
int ordered = 0; //...уже упорядоченных
long previousValue = arr [0];
for (int i = 1; i < arrSize; i ++)
{
long currentValue = arr [i];
if (currentValue > previousValue) greather ++;
else if (currentValue < previousValue) lesser ++;
else equals ++;
previousValue = currentValue;
}
ordered = arrSize - lesser;
printf ("меньше предыдущего элемента: %d равных предыдущему: %d больше предыдущего: %d\n",
lesser, equals, greather);
printf ("...всего упорядоченных элементов: %d\n", ordered);
}

//получить число секунд из структуры, содержащей секунды и микросекунды:
double getSec (struct timeval* timeVal)
{
return (double) timeVal->tv_sec + 0.000001 * timeVal->tv_usec;
}

//Вычесть значение времени y из x (где x > y). Результат - в result
//(заимствована из документации к библиотеке GCC, см. описание struct timeval)
int timeval_subtract (struct timeval* result, struct timeval* x, struct timeval* y)
{
/* Perform the carry for the later subtraction by updating y. */
if (x->tv_usec < y->tv_usec) {
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
y->tv_usec -= 1000000 * nsec;
y->tv_sec += nsec;
}
if (x->tv_usec - y->tv_usec > 1000000) {
int nsec = (x->tv_usec - y->tv_usec) / 1000000;
y->tv_usec += 1000000 * nsec;
y->tv_sec -= nsec;
}

/* Compute the time remaining to wait.
tv_usec is certainly positive. */
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_usec = x->tv_usec - y->tv_usec;

/* Return 1 if result is negative. */
return x->tv_sec < y->tv_sec;
}

int main (int ac, char* av[])
{
printf ("Демонстрация распараллеленной сортировки, %s\n", VERSION_LABEL);
//считаем время - во-первых, общее (по часам):
struct timeval start, end, span;
//во-вторых, время CPU:
clock_t startCPU, endCPU;

double allTestsTime [3] = {0, 0, 0};
double allTestsCPUTime [3] = {0, 0, 0};
int nTests = TESTS;
if (ac > 1)
{
nTests = atoi (av [1]);
if (errno || nTests <= 0)
{
printf ("Задано неправильное число циклов выполнения теста: %s\n", av [1]);
return 1;
}
}

printf ("Формат:\nomp_sort_ex [циклов, по умолчанию=%d]\n", TESTS);

//Узнать "число процессоров". Ядро тоже считается за процессор,
//а если есть поддержка Hyperthreading,то за несколько.
printf ("Число логических процессоров OpenMP:%d\n", omp_get_num_procs());

fillRandomArray (randoms, N, RANGE);
for (int i = 0; i < nTests; i ++)
{
printf ("**** %d из %d ****\n", i + 1, nTests);

//1. Обычная сортировка
printf ("Тест 1 - простое применение std::stable_sort для %d элементов\n", N);
std::copy (randoms, randoms + N, values);

putOrderInfo (values, N);
//узнать текущее время:
int error = gettimeofday (&start, NULL);//ошибки игнорируем
startCPU = clock ();//ещё измеряем время CPU

std::stable_sort (values, values + N);//сама сортировка

endCPU = clock ();
error = gettimeofday (&end, NULL);
error = timeval_subtract (&span, &end, &start);
double totalTime = getSec (&span);
double totalCPUTime = ((double) (endCPU - startCPU)) / CLOCKS_PER_SEC;
putOrderInfo (values, N);//проверим, как отсортировалось
//время сортировки - общее и процессорное:
printf ("время сортировки, сек: всего %12.3f процессорное %12.3f\n", totalTime, totalCPUTime);
allTestsTime [0] += totalTime;
allTestsCPUTime [0] += totalCPUTime;

//2. Сортировка в 2 потоках со слиянием результатов:
printf ("Тест 2 - 2-поточное выполнение std::stable_sort с последующим слиянием функцией std::inplace_merge\n");
std::copy (randoms, randoms + N, values);
putOrderInfo (values, N);
error = gettimeofday (&start, NULL);//узнать текущее время
startCPU = clock ();
int n2 = N / 2; //индекс для делёжки массива примерно пополам
#pragma omp parallel shared (values, n2) num_threads (2)
{
#pragma omp sections
{ //сортировка половин массива в разных потоках:
#pragma omp section
{
std::stable_sort (values, values + n2);
}
#pragma omp section
{
std::stable_sort (values + n2, values + N);
}
}
}
std::inplace_merge (values, values + n2, values + N);//сливаем половины
endCPU = clock ();
error = gettimeofday (&end, NULL);
error = timeval_subtract (&span, &end, &start);
totalTime = getSec (&span);
totalCPUTime = ((double) (endCPU - startCPU)) / CLOCKS_PER_SEC;
allTestsTime [1] += totalTime;
allTestsCPUTime [1] += totalCPUTime;

putOrderInfo (values, N);
printf ("время 2-поточной сортировки, сек: всего %12.3f процессорное %12.3f\n", totalTime, totalCPUTime);

//1. Сортировка параллелизованной функцией (GCC 4.4)
printf ("Тест 3 - параллелизованная функция __gnu_parallel::stable_sort для %d элементов\n", N);
std::copy (randoms, randoms + N, values);

putOrderInfo (values, N);
//узнать текущее время:
error = gettimeofday (&start, NULL);//ошибки игнорируем
startCPU = clock ();//ещё измеряем время CPU

__gnu_parallel::stable_sort (values, values + N);//сама сортировка

endCPU = clock ();
error = gettimeofday (&end, NULL);
error = timeval_subtract (&span, &end, &start);
totalTime = getSec (&span);
totalCPUTime = ((double) (endCPU - startCPU)) / CLOCKS_PER_SEC;
putOrderInfo (values, N);//проверим, как отсортировалось
//время сортировки - общее и процессорное:
printf ("время сортировки, сек: всего %12.3f процессорное %12.3f\n", totalTime, totalCPUTime);
allTestsTime [2] += totalTime;
allTestsCPUTime [2] += totalCPUTime;

}

double sumTime = 0;
double sumCPU = 0;
printf ("------------ Результат ----------------\n");
for (int i = 1; i <= 3; i ++)
{
double testTime = allTestsTime [i-1];
double testCPU = allTestsCPUTime [i-1];
sumTime += testTime;
sumCPU += testCPU;

printf ("Время теста номер %d, сек: %g (процессорное: %g)\nСреднее время: %g (процессорное: %g)\n",
i, testTime, testCPU, testTime / nTests, testCPU /nTests);
}
printf ("Суммарное время тестов, сек: %g (процессорное: %g)\nСреднее время, сек: %g (процессорное: %g)\n",
sumTime, sumCPU, sumTime / nTests, sumCPU /nTests);

return 0;

}
/SRC]
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36052404
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Отформатировал.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
/**
 * OMP_SORT_EX
 *
 * версия 1.4 добавлен тест функций __gnu_parallel::*
 * Компиляция:
 * g++ -fopenmp -O2 omp_sort_ex.cpp -o omp_sort_ex -lgomp
 *
 * Выполнение:
 * ./omp_sort_ex [число циклов тестирования]
 *
 * версия 1.3
 *
 * - добавлено испытание параллельной версии
 * функции сортировки (требуется GCC 4.4).
 * - сообщения переведены на русский язык
 * - название программы изменено с omp_sort на opm_sort_ex.
 * Компиляция:
 * g++ -fopenmp -O2 -march=native -D_GLIBCXX_PARALLEL omp_sort_ex.cpp -o omp_sort_ex -lgomp
 *
 * Проверено в Fedora 11, 64-битной.
 *
 * версия 1.2
 *
 * - добавлено выполнение в цикле
 *
 * версия 1.1
 *
 * - используется std::stable_sort вместо std::sort
 *
 * Демонстрация многопоточной сортировки.
 * Требуется компилятор с поддержкой OpenMP (http://www.openmp.org),
 * например GCC версии 4.2.1 и выше (для RedHat - от 4.1.1).
 * Проверено в CentOS 5.0 386 с GCC 4.1.1.
 *
 * Компиляция:
 * g++ -fopenmp -O2 omp_sort.cpp -o omp_sort -lgomp
 *
 * Здесь ключ -O2 (оптимизация) не обязателен, но значительно увеличивает скорость теста.
 * Добавить другие необязательные ключи по вкусу.
 * Ключ -lgomp обязателен только при использовании библиотеки libgomp,
 * то есть, если в программе используются функции OpenMP,
 * а не только директивы OpenMP (многопоточность можно создать одними директивами).
 *
 * Библиотека libgomp - в RedHat имеет свой RPM пакет.
 * Искать libgomp надо в /usr/lib.
 *
 * Вызов:
 * ./opm_sort [100]
 * где необязательный параметр - число повторений
 * (выполнение в цикле - чтобы проверить правильность
 * общего показываемого времени вручную и для устреднения результатов,
 * а то они сильно колеблются).
 *
 */


#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <algorithm>
#include <parallel/algorithm>


#define VERSION_LABEL "v.1.4"
#define N 25000000L //размер сортируемого массива
#define RANGE  100000000  //диапазон изменения случ. чисел
#define TESTS  10  //количество циклов тестов



long values [N]; //массив для сортировки
long randoms [N]; //заполняем случайными числами один раз,а потом копируем в values

//Заполнить массив случайными числами от 0 до range-1.
//Не переносимо в Visual Studio, поскольку там RAND_MAX маленькое (32767),
//в то время как для GCC оно вполне приличное (2147483647):

void fillRandomArray(long* arr, int arrSize, int range) {

    srand(time( 0 ));
    for (int i =  0 ; i < arrSize; i++) {
        arr [i] = (long) ((double) rand() / (double) RAND_MAX * range);
    }
}

//Показать, какова упорядоченность массива. Вызывается до и после сортировки

void putOrderInfo(long* arr, int arrSize) { //сколько элементов:
    int lesser =  0 ; //...меньше предыдущего
    int equals =  0 ; //...равных предыдыдущему
    int greather =  0 ; //...больше предыдущего
    int ordered =  0 ; //...уже упорядоченных
    long previousValue = arr [ 0 ];
    for (int i =  1 ; i < arrSize; i++) {
        long currentValue = arr [i];
        if (currentValue > previousValue) greather++;
        else if (currentValue < previousValue) lesser++;
        else equals++;
        previousValue = currentValue;
    }
    ordered = arrSize - lesser;
    printf("меньше предыдущего элемента: %d равных предыдущему: %d больше предыдущего: %d\n",
            lesser, equals, greather);
    printf("...всего упорядоченных элементов: %d\n", ordered);
}

//получить число секунд из структуры, содержащей секунды и микросекунды:

double getSec(struct timeval* timeVal) {
    return (double) timeVal->tv_sec +  0 . 000001  * timeVal->tv_usec;
}

//Вычесть значение времени y из x (где x > y). Результат - в result
//(заимствована из документации к библиотеке GCC, см. описание struct timeval)

int timeval_subtract(struct timeval* result, struct timeval* x, struct timeval* y) {
    /* Perform the carry for the later subtraction by updating y. */
    if (x->tv_usec < y->tv_usec) {
        int nsec = (y->tv_usec - x->tv_usec) /  1000000  +  1 ;
        y->tv_usec -=  1000000  * nsec;
        y->tv_sec += nsec;
    }
    if (x->tv_usec - y->tv_usec >  1000000 ) {
        int nsec = (x->tv_usec - y->tv_usec) /  1000000 ;
        y->tv_usec +=  1000000  * nsec;
        y->tv_sec -= nsec;
    }

    /* Compute the time remaining to wait.
    tv_usec is certainly positive. */
    result->tv_sec = x->tv_sec - y->tv_sec;
    result->tv_usec = x->tv_usec - y->tv_usec;

    /* Return 1 if result is negative. */
    return x->tv_sec < y->tv_sec;
}

int main(int ac, char* av[]) {
    printf("Демонстрация распараллеленной сортировки, %s\n", VERSION_LABEL);
    //считаем время - во-первых, общее (по часам):
    struct timeval start, end, span;
    //во-вторых, время CPU:
    clock_t startCPU, endCPU;

    double allTestsTime [ 3 ] = { 0 ,  0 ,  0 };
    double allTestsCPUTime [ 3 ] = { 0 ,  0 ,  0 };
    int nTests = TESTS;
    if (ac >  1 ) {
        nTests = atoi(av [ 1 ]);
        if (errno || nTests <=  0 ) {
            printf("Задано неправильное число циклов выполнения теста: %s\n", av [ 1 ]);
            return  1 ;
        }
    }

    printf("Формат:\nomp_sort_ex [циклов, по умолчанию=%d]\n", TESTS);

    //Узнать "число процессоров". Ядро тоже считается за процессор,
    //а если есть поддержка Hyperthreading,то за несколько.
    printf("Число логических процессоров OpenMP:%d\n", omp_get_num_procs());

    fillRandomArray(randoms, N, RANGE);
    for (int i =  0 ; i < nTests; i++) {
        printf("**** %d из %d ****\n", i +  1 , nTests);

        //1. Обычная сортировка
        printf("Тест 1 - простое применение std::stable_sort для %d элементов\n", N);
        std::copy(randoms, randoms + N, values);

        putOrderInfo(values, N);
        //узнать текущее время:
        int error = gettimeofday(&start, NULL); //ошибки игнорируем
        startCPU = clock(); //ещё измеряем время CPU

        std::stable_sort(values, values + N); //сама сортировка

        endCPU = clock();
        error = gettimeofday(&end, NULL);
        error = timeval_subtract(&span, &end, &start);
        double totalTime = getSec(&span);
        double totalCPUTime = ((double) (endCPU - startCPU)) / CLOCKS_PER_SEC;
        putOrderInfo(values, N); //проверим, как отсортировалось
        //время сортировки - общее и процессорное:
        printf("время сортировки, сек: всего %12.3f процессорное %12.3f\n", totalTime, totalCPUTime);
        allTestsTime [ 0 ] += totalTime;
        allTestsCPUTime [ 0 ] += totalCPUTime;

        //2. Сортировка в 2 потоках со слиянием результатов:
        printf("Тест 2 - 2-поточное выполнение std::stable_sort с последующим слиянием функцией std::inplace_merge\n");
        std::copy(randoms, randoms + N, values);
        putOrderInfo(values, N);
        error = gettimeofday(&start, NULL); //узнать текущее время
        startCPU = clock();
        int n2 = N /  2 ; //индекс для делёжки массива примерно пополам
#pragma omp parallel shared (values, n2) num_threads ( 2 )
        {
#pragma omp sections
            { //сортировка половин массива в разных потоках:
#pragma omp section
                {
                    std::stable_sort(values, values + n2);
                }
#pragma omp section
                {
                    std::stable_sort(values + n2, values + N);
                }
            }
        }
        std::inplace_merge(values, values + n2, values + N); //сливаем половины
        endCPU = clock();
        error = gettimeofday(&end, NULL);
        error = timeval_subtract(&span, &end, &start);
        totalTime = getSec(&span);
        totalCPUTime = ((double) (endCPU - startCPU)) / CLOCKS_PER_SEC;
        allTestsTime [ 1 ] += totalTime;
        allTestsCPUTime [ 1 ] += totalCPUTime;

        putOrderInfo(values, N);
        printf("время 2-поточной сортировки, сек: всего %12.3f процессорное %12.3f\n", totalTime, totalCPUTime);

        //1. Сортировка параллелизованной функцией (GCC 4.4)
        printf("Тест 3 - параллелизованная функция __gnu_parallel::stable_sort для %d элементов\n", N);
        std::copy(randoms, randoms + N, values);

        putOrderInfo(values, N);
        //узнать текущее время:
        error = gettimeofday(&start, NULL); //ошибки игнорируем
        startCPU = clock(); //ещё измеряем время CPU

        __gnu_parallel::stable_sort(values, values + N); //сама сортировка

        endCPU = clock();
        error = gettimeofday(&end, NULL);
        error = timeval_subtract(&span, &end, &start);
        totalTime = getSec(&span);
        totalCPUTime = ((double) (endCPU - startCPU)) / CLOCKS_PER_SEC;
        putOrderInfo(values, N); //проверим, как отсортировалось
        //время сортировки - общее и процессорное:
        printf("время сортировки, сек: всего %12.3f процессорное %12.3f\n", totalTime, totalCPUTime);
        allTestsTime [ 2 ] += totalTime;
        allTestsCPUTime [ 2 ] += totalCPUTime;

    }

    double sumTime =  0 ;
    double sumCPU =  0 ;
    printf("------------ Результат ----------------\n");
    for (int i =  1 ; i <=  3 ; i++) {
        double testTime = allTestsTime [i -  1 ];
        double testCPU = allTestsCPUTime [i -  1 ];
        sumTime += testTime;
        sumCPU += testCPU;

        printf("Время теста номер %d, сек: %g (процессорное: %g)\nСреднее время: %g (процессорное: %g)\n",
                i, testTime, testCPU, testTime / nTests, testCPU / nTests);
    }
    printf("Суммарное время тестов, сек: %g (процессорное: %g)\nСреднее время, сек: %g (процессорное: %g)\n",
            sumTime, sumCPU, sumTime / nTests, sumCPU / nTests);

    return  0 ;

}
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36053006
aleks2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gluk (Kazan),

>>так пойдет ?
Не пойдет. Мое время стоит денег, а сама по себе эта задача меня не интересует.

>>Для того, чтобы задачка ХОРОШО (а не просто абы как) параллелилось, желательно чтобы параллельные процессы выполняли по возможности одинаковый объем работ
Размер, в данном случае, не имеет значения. Разделил один - дели следующий.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36053018
Фотография Gluk (Kazan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aleks2Gluk (Kazan),

>>так пойдет ?
Не пойдет. Мое время стоит денег, а сама по себе эта задача меня не интересует.


Прикинь, мое тоже :)
ладно, в ощем, слив засчитан
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36053020
Фотография Gluk (Kazan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Partisan MGluk (Kazan)На 2 вообще понту нет (особенно ядрах)
Есть понт даже и на двух. Далее привожу результаты тестов.


Ты знаешь, фраза про понты звучала в контексте распараллеливания QuickSort-а, не надо выдирать ее из этого контекста. Сортировка кусочков массива с последующим слиянием несколько более удобная для параллельного выполнения задача. О чем я собственно уже говорил: тут
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36053022
Фотография Gluk (Kazan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aleks2Gluk (Kazan),

>>Для того, чтобы задачка ХОРОШО (а не просто абы как) параллелилось, желательно чтобы параллельные процессы выполняли по возможности одинаковый объем работ
Размер, в данном случае, не имеет значения. Разделил один - дели следующий.

1. Размер имеет значение (на массивах небольшого размера сортировка простыми вставками вполне может сделать и QuickSort и HeapSort)
2. Разница размеров имеет еще большее значение, потому что всем придется ждать самого медленного
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36053077
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Partisan M.

Спасибо за исходник. Добавлю в свою коллекцию. Щас пока скомпилировать не могу. Нет условий. Попробую чуть позже.

Еще-бы неплохо рассмотреть варианты исходных данных типа:

1) Возрастающая последовательность.
2) Убывающая последовательность
3) Случайная с линейным распределением
4) Случайная с характерным "перекосом" (распр. Гаусса например).
5) Пакет возрастающих (или убывающих) подпоследовательностей.

В этом случае бенчмарк будет иметь еще и рекомендации по применению. Это было-бы здорово.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36058585
Partisan M
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonВ этом случае бенчмарк будет иметь еще и рекомендации по применению. Это было-бы здорово.

Я ограничился сортировкой равномерно-распределённых случайных значений, потому что этот тест хорошо показывает эффект от распараллеливания. Для других распределений на результат будет влиять и поведение самого алгоритма.
Значит, сейчас быстродействие по-видимому близко к оптимальному, потому что результат мало отличается от внутренне распараллеленной функции __gnu_parallel::stable_sort. Небольшое отставание я думаю (хотя проверию) объясняется не небольшой неоптимальностью моего способа, а тем, что производится анализ возможности распараллелить std::sort в каждом из потоков (с заменой на __gnu_parallel::stable_sort), но оно не имеет смысла, т.к. есть только 2 ядра.

Однако если бы распределение было не равномерным, а одним из предлагаемых вами, то быстродействие моего способа стало бы не оптимальным, из-за отсутствия балансировки потоков.
Действительно, скорость сортировки в какой-то степени зависит от распределения. Если оно неодинаковое в половинах массива, то скорость сортировки половин будет неодинаковой, и один поток будет простаивать.
Для борьбы с этим я придумал способ - делить на большее число подмассивов. Скажем, на 10 вместо 2 итд (в зависимости от числа ядер). Тогда если поток закончит сортировать один отрезок, он может приняться за сортировку ещё одного. Кстати, OpenMP имеет простое средство создания такой очереди задач на подмассивов для потоков. Ещё надо бы добавить автоматическое определение числа потоков по числу процессоров.
То и другое сделать легко. Как найду время, то модифицирую свой пример, тогда он и станет вполне практичной программой сортировки. А пока что он демонстрирует идею распараллеливания сортировки.
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36081058
Игорь Ковалев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ссылка по теме http://www3.lehigh.edu/images/userImages/jgs2/Page_3813/LU-CSE-05-002.pdf
...
Рейтинг: 0 / 0
Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
    #36084329
rmull
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Насчёт изначальной задачи. Если у вас массив байтов , то почему бы не использовать сортировку подсчётом?
...
Рейтинг: 0 / 0
35 сообщений из 35, показаны все 2 страниц
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Сортировка блока в памяти 100Мб quick sort vs сортировка слиянием
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]