Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Сортировка слиянием с помощью pthread, Смущает производительность 
V
    Опции темы
NoviceF
Дата 6.11.2012, 08:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: 2



Вопрос, наверное, из раздела для начинающих, но там вроде бы не встречал вопросов по многопоточности, поэтому пишу сюда.

Суть проблемы в следующем - задача отсортировать вектор интов с помощью 2х(!) потоков и получить заметный прирост производительности, по сравнению с однопоточным вариантом.

есть такой код
Код

#include <vector>
#include <iostream>
#include <ctime>
#include <typeinfo>

typedef std::vector<int> intvec;

intvec merge(intvec a, intvec b);

intvec merge_sort(intvec a) {
    if (a.size() <= 1)
        return a;
    intvec b, c;
    b.assign(a.begin(), a.end()-(a.size() / 2));
    c.assign(a.end()-(a.size() / 2), a.end());
    return merge(merge_sort(b), merge_sort(c));
}

void * f(void * arg) {

    intvec &c = *(static_cast<intvec*>(arg));
    
    c = merge_sort(c);
    
    return 0;

}

int main()
{
    intvec m;
    
    m.reserve(1000000);
    
    srand(time(NULL));
    for (int i = 0; i < 1000000; ++i) {
        m.push_back(rand() % 100);
    }
    
//     std::cout << "size of m = " << m.size() << std::endl;
    
    intvec n1,n2;
    n1.assign(m.begin(), m.end()-(m.size() / 2));
    n2.assign(m.end()-(m.size() / 2), m.end());
    
/*    for (int i = 0; i < static_cast<int>(m.size()); ++i) {
        std::cout << m[i] << " " << std::endl;
    } 
*/
    
    pthread_t tid1, tid2;
    int ret;
    
    ret = pthread_create(&tid1, NULL, f, &n1);
    if (ret) {
        printf("%d %s - unable to create thread - ret - %d\n", __LINE__, __FUNCTION__, ret);
        exit(1);
    }
    ret = pthread_create(&tid2, NULL, f, &n2);
    if (ret) {
        printf("%d %s - unable to create thread - ret - %d\n", __LINE__, __FUNCTION__, ret);
        exit(1);
    }

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL); 
    
    m = merge (n1,n2);
    
/*    std::cout << std::endl;
    
    for (int i = 0; i < static_cast<int>(m.size()); ++i) {
    
        std::cout << m[i] << " " << std::endl;
    
    }  
*/
        
    return 0;
}

intvec merge(intvec a, intvec b) {
    intvec c(a.size() + b.size());

    int count1 = 0;
    int count2 = 0;

    for (int i = 0; i < static_cast<int> (c.size()); ++i) {

        if (count1 == static_cast<int> (a.size())) {
            c[i] = b[count2];
            count2++;
            continue;
        }

        if (count2 == static_cast<int> (b.size())) {
            c[i] = a[count1];
            count1++;
            continue;
        }


        if (a[count1] <= b[count2]) {
            c[i] = a[count1];
            count1++;
        } else {
            c[i] = b[count2];
            count2++;
        }

    }
    return c;
}

http://liveworkspace.org/code/33f03fd7f5a3...dcf521c4ea53fb2

это сортировка слиянием, выполненная, видимо, странным и неправильным образом. Там берётся вектор, делится на 2 отдельных вектора пополам, после чего каждый из 2х получившихся полувекторов отдаётся потоку для сортировки (всего 2 потока). После того, как потоки производят сортировку каждый своего вектора, эти векторы объединяются в один с помощью того же слияния. 

Проблема заключается в том, что по сравнению с однопоточной версией, производительность(ну то есть по моим представлениям это время выполнения программы) либо не меняется, либо падает.

Вопросы такой: как по-другому можно организовать "сортировку вектора в 2 потока", чтобы получить видимый прирост в производительности по сравнению с однопоточной версией.

Спасибо.

PM MAIL   Вверх
borisbn
Дата 6.11.2012, 09:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Если проверяешь на Debug-версии, то результат может быть какой угодно. Проверь на Release.
Если же проверяешь на Release, то результат тоже можно попытаться объяснить


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
NoviceF
Дата 6.11.2012, 10:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: 2



Цитата(borisbn @  6.11.2012,  10:18 Найти цитируемый пост)
Если проверяешь на Debug-версии, то результат может быть какой угодно.


Да, проверял на дэбаге, попробую на релизе значит..
PM MAIL   Вверх
baldina
Дата 6.11.2012, 10:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



на релизе скорее всего однопоточная тоже обгонит

Добавлено через 1 минуту и 57 секунд
копируются большие массивы данных, в многопоточной идет постоянная перезагрузка кэша, в отличие от однопоточной
не проверял, это из общих соображений.
PM MAIL   Вверх
NoviceF
Дата 6.11.2012, 11:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: 2



Цитата(baldina @  6.11.2012,  11:55 Найти цитируемый пост)
не проверял, это из общих соображений. 


А как организовать программу, чтобы был прирост при сортировке в 2 потока? 

У меня откуда-то есть предположение, что основной упор делается на то, что однопоточные приложения обрабатываются одним ядром ЦПУ, если потоков больше, должно задействоваться и второе.. Может какой-то ключ при компиляции  добавлять?  smile 
PM MAIL   Вверх
baldina
Дата 6.11.2012, 13:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



ключи компиляции не помогут. да и нет таких ключей.
если задача, скажем так, вычислительная, т.е. требующая в основном ресурсы процессора, то производительность можно улучшить практически пропорционально числу процессоров. 
если задействованы и другие ресурсы, например память (а это наиболее частый случай), все становится гораздо менее однозначно.
в вашей сортировке используются большие массивы данных, которые, к тому же, копируются туда-сюда. 
думаю сортировка слиянием в наивной реализации - не лучшая задача для параллелизма.

почитайте для начала по ссылкам, интересно
http://habrahabr.ru/post/143055/
http://kimrgrey.livejournal.com/4775.html

еще припоминаю одну историю: был конкурс на написание одной программы. не помню, что она должна была делать, помню только что это конкурс intel на лучшую многопоточную программу.
некоторое время первое место было за программой, написанной на С++. и вот появилась программа (она и заняла 1е место), которая была производительней в 6(!) раз. Если сравнить код, программы практически идентичны, отличались парой строк (т.е. логически они делали одно и то же одинаковым способом), только потоки запускаются в другой последовательности. программа победителя выясняла, какие ядра относятся к одному процессору (а значит у них общий кэш), и на основе этого распределяла потоки.

PM MAIL   Вверх
borisbn
Дата 6.11.2012, 13:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Ещё у azesmcar в подписи интересная ссылка (не конкретно про сортировку, а вообще о многопоточности)


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
baldina
Дата 6.11.2012, 14:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



особенно эта http://www.data-race.com/2011/01/14/%D0%B4...B5%D0%B4%D0%B5/

Добавлено через 2 минуты и 31 секунду
Есть интересный алгоритм сортировки слиянием на основе построения бимонотонной (т.е. состоящей из двух монотонных частей) последовательности, Bitonic Merge Sort
PM MAIL   Вверх
NoviceF
Дата 6.11.2012, 14:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: 2



Спасибо за комменты, буду ознакамливаться.
PM MAIL   Вверх
volatile
Дата 6.11.2012, 23:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(NoviceF @  6.11.2012,  08:41 Найти цитируемый пост)
intvec merge_sort(intvec a) {
    if (a.size() <= 1)
        return a;
    intvec b, c;
    b.assign(a.begin(), a.end()-(a.size() / 2));
    c.assign(a.end()-(a.size() / 2), a.end());
    return merge(merge_sort(b), merge_sort©);
}

Умопомрачительная процедура!
Вектора миллионного размера, прямым копированием, да еще в рекурсии. smile
Естественно тут не дополнительное ядро процессора нужно, а дополнительный DMA контроллер с дополнительной шиной данных (интересно такое вообще бывает?)
NoviceF,  есть же в языке константные ссылки (указатели в конце концов).
Нужно пользоваться ими, начиная уже со структур размером > разрядности платформы (т.е. > 4/8 байтов) 
А уж мегабайтные вектора передавать копированием, это самоубийство.
Хорошо, если у вас оптимизатор сам подставил ссылки (в чем я очень и очень сомневаюсь).

PM MAIL   Вверх
NoviceF
Дата 7.11.2012, 08:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: 2



Цитата(volatile @  7.11.2012,  00:53 Найти цитируемый пост)
Вектора миллионного размера, прямым копированием, да еще в рекурсии. 


Вопрос был не в эффективности самого алгоритма, т.к. оба подхода и однопоточный и двухпоточный использовали одну и ту же реализацию алгоритма. Писал его не я и, честно говоря, было ещё чем заняться, кроме как оптимизацией алгоритма smile


И хотелось бы покаяться перед всеми отписавшимися, т.к. вся инфа, что я писал выше получилось в результате кривой проверки, хотя о том, что она кривая я как-то не задумывался. Дело в том, что тестировал я следующим образом, сделал в одном проекте 2 срр файла, с функцией main в каждом, после чего для теста исключал из сборки первый файл, компилировал, проверял. Затем наоборот исключал 2й файл, отменял исключение первого, компилировал, проверял.. Ну и там ещё иногда использовался ключ для профилировщика gprof.

Вчера решил всётаки ради эксперимента разбить на 2 проекта.. и результат удивил.. В общем двухпоточная версия выполняется на 60-80% быстрее.. Так что извиняюсь за то, что ввёл в заблуждение.

Ну и вопрос, может у кого есть идеи, почему при первом варианте (с двумя поочередёно отключаемыми cpp файлами в одном проекте) результат был одинаковыми, хотя в сборке учавствовали файлы с разным кодом?

Это сообщение отредактировал(а) NoviceF - 7.11.2012, 08:33
PM MAIL   Вверх
volatile
Дата 7.11.2012, 12:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(NoviceF @  7.11.2012,  08:21 Найти цитируемый пост)
Ну и вопрос, может у кого есть идеи, почему при первом варианте (с двумя поочередёно отключаемыми cpp файлами в одном проекте) результат был одинаковыми, хотя в сборке учавствовали файлы с разным кодом?

Скорей всего у вас в ваших проектах разные настройки. (не только оптимизация)
Для надежности нужно в одном проекте собирать.
Т.е. первый случай как-раз более корректный.

PM MAIL   Вверх
azesmcar
Дата 21.3.2013, 21:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата(baldina @  6.11.2012,  13:43 Найти цитируемый пост)
еще припоминаю одну историю: был конкурс на написание одной программы. не помню, что она должна была делать, помню только что это конкурс intel на лучшую многопоточную программу.
некоторое время первое место было за программой, написанной на С++. и вот появилась программа (она и заняла 1е место), которая была производительней в 6(!) раз. Если сравнить код, программы практически идентичны, отличались парой строк (т.е. логически они делали одно и то же одинаковым способом), только потоки запускаются в другой последовательности. программа победителя выясняла, какие ядра относятся к одному процессору (а значит у них общий кэш), и на основе этого распределяла потоки.

Если кому-то еще интересно. В блоге победителя конкурса есть подробное описание

http://www.1024cores.net/home/in-russian/h...-i-ocen-bystrye
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0619 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.