Что быстрее в Visual C ++ 2010 - std :: shared_ptr или boost :: shared_ptr?

Кто-нибудь тестировал это в сборках в режиме выпуска? Или реализации настолько похожи, что нет существенной разницы?

Меня интересует скорость:

  1. Создайте новый shared_ptr

  2. Создайте копию shared_ptr

  3. Отмените ссылку на указатель, чтобы получить доступ к указателю

Это будет в сборке релиза, оптимизированной для скорости, с новыми shared_ptrs, создаваемыми с помощью make_shared ()


person mpipe3    schedule 24.06.2011    source источник
comment
Почему бы тебе самому не измерить? Думаю, ощутимой разницы не будет.   -  person Yakov Galka    schedule 24.06.2011
comment
std::shared_ptr обычно основан на boost::shared_ptr, но я думаю, что версия std:: теоретически могла бы быть быстрее, потому что в ней разрешено использовать специфичную для компилятора поддержку, которой у Boost может не быть. Но я думаю, что обычно они будут одинаково быстрыми; тем не менее, когда сомневаетесь в мере.   -  person Matteo Italia    schedule 24.06.2011
comment
Достаточно ли часто вы выполняете эти операции, чтобы это имело значение.   -  person Greg    schedule 24.06.2011
comment
@sven Я надеялся, что это уже кто-то сделал. Отсюда вопрос. Если нет, то попробую и выложу результаты.   -  person mpipe3    schedule 24.06.2011
comment
@Matteo Italia: У библиотек Boost довольно много знаний о компиляторах. Тот факт, что они являются мультиплатформенными, не означает, что они не используют каждую платформу, на которой они скомпилированы.   -  person David Rodríguez - dribeas    schedule 24.06.2011
comment
Другая проблема, которая может быть актуальной, заключается в том, что по моему опыту (по крайней мере, для VS2008) при использовании версии boost существует немного больше накладных расходов компилятора с точки зрения количества других файлов, которые он втягивает, тогда как заголовок Visual Studio намного компактнее. Будет ли это важно для вас, будет зависеть от размера вашей сборки, использования файлов PCH и т. Д.   -  person the_mandrill    schedule 27.06.2011


Ответы (2)


Хорошо, так что не похоже, что кто-то это сделал. Вот что я нашел, используя стандартные оптимизированные настройки VC 10 для консольного приложения WIN32:

  1. Visual C ++ 2010 с пакетом обновления 1 (SP1) std :: make_shared и std :: shared_ptr были быстрее, чем эквиваленты Boost 1.46.1, при заполнении вектора из 10 миллионов записей указателя (1,96 секунды против 0,92 секунды, усредненных по 20 запускам)

  2. Boost 1.46.1 был немного быстрее, чем Visual C ++ 2010 SP1, при копировании массива из 10 миллионов записей указателя (0,15 секунды против 0,17 секунды в среднем за 20 запусков)

  3. Visual C ++ 2010 SP1 был немного быстрее, чем эквиваленты Boost 1.46.1, при 20 раз разыменовании вектора из 10 миллионов записей указателя (0,72 секунды против 0,811 секунды, усредненных за 20 запусков)

ЗАКЛЮЧЕНИЕ: при создании shared_ptrs для заполнения вектора была значительная разница. Visual C ++ 2010 shared_ptr был почти в два раза быстрее, что указывает на существенную разницу в реализации по сравнению с Boost 1.46.1.

Остальные тесты не показали существенной разницы.

Вот код, который я использовал:

#include "stdafx.h"

struct A
{
    A( const unsigned A) : m_value(A)
    {
    }

    const unsigned m_value;
};

typedef std::shared_ptr<A> APtr;
typedef boost::shared_ptr<A> ABoostPtr;


double TestSTLCreateSpeed()
{
    const unsigned NUM_ENTRIES = 10000000;
    std::vector<APtr> buffer;
    buffer.reserve(NUM_ENTRIES);

    boost::timer timer;

    for( unsigned nEntry = 0; nEntry < NUM_ENTRIES; ++nEntry)
    {
        buffer.emplace_back( std::make_shared<A>(nEntry) );
    }

    const double timeTaken = timer.elapsed();

    std::cout << "STL create test took " << timeTaken << " secs.\r\n";
    return timeTaken;
}

double BoostSTLCreateSpeed()
{
    const unsigned NUM_ENTRIES = 10000000;
    std::vector<ABoostPtr> buffer;
    buffer.reserve(NUM_ENTRIES);

    boost::timer timer;

    for( unsigned nEntry = 0; nEntry < NUM_ENTRIES; ++nEntry)
    {
        buffer.emplace_back( boost::make_shared<A>(nEntry) );
    }

    const double timeTaken = timer.elapsed();

    std::cout << "BOOST create test took " << timeTaken << " secs.\r\n";
    return timeTaken;
}

double TestSTLCopySpeed()
{
    const unsigned NUM_ENTRIES = 10000000;
    std::vector<APtr> buffer;
    buffer.reserve(NUM_ENTRIES);

    for( unsigned nEntry = 0; nEntry < NUM_ENTRIES; ++nEntry)
    {
        buffer.emplace_back( std::make_shared<A>(nEntry) );
    }

    boost::timer timer;
    std::vector<APtr> buffer2 = buffer;

    const double timeTaken = timer.elapsed();

    std::cout << "STL copy test took " << timeTaken << " secs.\r\n";
    return timeTaken;
}

double TestBoostCopySpeed()
{
    const unsigned NUM_ENTRIES = 10000000;
    std::vector<ABoostPtr> buffer;
    buffer.reserve(NUM_ENTRIES);

    for( unsigned nEntry = 0; nEntry < NUM_ENTRIES; ++nEntry)
    {
        buffer.emplace_back( boost::make_shared<A>(nEntry) );
    }

    boost::timer timer;
    std::vector<ABoostPtr> buffer2 = buffer;

    const double timeTaken = timer.elapsed();

    std::cout << "BOOST copy test took " << timeTaken << " secs.\r\n";
    return timeTaken;
}

double TestBoostDerefSpeed()
{
    const unsigned NUM_ENTRIES = 10000000;
    std::vector<ABoostPtr> buffer;
    buffer.reserve(NUM_ENTRIES);

    for( unsigned nEntry = 0; nEntry < NUM_ENTRIES; ++nEntry)
    {
        buffer.emplace_back( boost::make_shared<A>(nEntry) );
    }

    boost::timer timer;

    unsigned total = 0;

    for(unsigned nIter = 0; nIter < 20; ++nIter)
    {
        std::for_each( buffer.begin(), buffer.end(),
            [&](const ABoostPtr& pA){ 
                total += pA->m_value;
        });
    }

    const double timeTaken = timer.elapsed();

    std::cout << "BOOST deref total =  " << total << ".\r\n";

    std::cout << "BOOST deref test took " << timeTaken << " secs.\r\n";
    return timeTaken;
}

double TestSTLDerefSpeed()
{
    const unsigned NUM_ENTRIES = 10000000;
    std::vector<APtr> buffer;
    buffer.reserve(NUM_ENTRIES);

    for( unsigned nEntry = 0; nEntry < NUM_ENTRIES; ++nEntry)
    {
        buffer.emplace_back( std::make_shared<A>(nEntry) );
    }

    boost::timer timer;

    unsigned total = 0;
    for(unsigned nIter = 0; nIter < 20; ++nIter)
    {
        std::for_each( buffer.begin(), buffer.end(),
            [&](const APtr& pA){ 
                total += pA->m_value;
        });
    }

    const double timeTaken = timer.elapsed();

    std::cout << "STL deref total =  " << total << ".\r\n";

    std::cout << "STL deref test took " << timeTaken << " secs.\r\n";
    return timeTaken;
}

int _tmain(int argc, _TCHAR* argv[])
{
    double totalTime = 0.0;
    const unsigned NUM_TESTS = 20;

    totalTime = 0.0;

    for ( unsigned nTest = 0; nTest < NUM_TESTS; ++nTest)
    {
        totalTime += BoostSTLCreateSpeed();
    }

    std::cout << "BOOST create test took " << totalTime / NUM_TESTS << " secs average.\r\n";

    totalTime = 0.0;
    for ( unsigned nTest = 0; nTest < NUM_TESTS; ++nTest)
    {
        totalTime += TestSTLCreateSpeed();
    }

    std::cout << "STL create test took " << totalTime / NUM_TESTS << " secs average.\r\n";


    totalTime = 0.0;
    for ( unsigned nTest = 0; nTest < NUM_TESTS; ++nTest)
    {
        totalTime += TestBoostCopySpeed();
    }

    std::cout << "BOOST copy test took " << totalTime / NUM_TESTS << " secs average.\r\n";

    totalTime = 0.0;
    for ( unsigned nTest = 0; nTest < NUM_TESTS; ++nTest)
    {
        totalTime += TestSTLCopySpeed();
    }

    std::cout << "STL copy test took " << totalTime / NUM_TESTS << " secs average.\r\n";

    totalTime = 0.0;
    for ( unsigned nTest = 0; nTest < NUM_TESTS; ++nTest)
    {
        totalTime += TestBoostDerefSpeed();
    }

    std::cout << "Boost deref test took " << totalTime / NUM_TESTS << " secs average.\r\n";

    totalTime = 0.0;
    for ( unsigned nTest = 0; nTest < NUM_TESTS; ++nTest)
    {
        totalTime += TestSTLDerefSpeed();
    }

    std::cout << "STL deref test took " << totalTime / NUM_TESTS << " secs average.\r\n";

    return 0;
}

Я подожду некоторое время, и если никто не опровергнет мои результаты или не придет к лучшим выводам, я приму свой ответ.

person mpipe3    schedule 27.06.2011
comment
Спасибо, что нашли время сообщить о своих результатах. - person ; 27.06.2011
comment
Спасибо за этот отчет. Теперь вы также можете протестировать поведение удаления с помощью специального средства удаления, так как это также важная часть, которая часто используется, особенно для shared_ptr<void>. - person Xeo; 30.06.2011
comment
Есть идеи, что в реализации VS делает это быстрее? Я хорошо знаком с реализацией ускорения, и у меня нет очевидного способа улучшить ее. Может быть, он делает непереносимые предположения, основываясь на знании того, что распределитель MS используется? - person Joseph Garvin; 14.12.2012

Версия VS10 использует ссылки rvalue и семантику перемещения, когда это возможно, поэтому в принципе имеет преимущество над реализацией Boost C ++ 98. Вам, вероятно, придется потрудиться, чтобы создать программу, которая показала бы значительную практическую разницу, хотя ... но попробуйте. Также не забывайте о std::make_shared, который появился в C ++ 0x благодаря пересылке.

Обновление: разыменование и копирование в любом случае будут практически идентичными. Возможно, есть некоторые интересные различия в способах хранения пользовательских удалителей и распределителей, а также в том, как реализован make_shared. Позвольте мне проверить источник.

Обновление 2: как ни странно, версия Boost, в которой используются вариативные шаблоны и ссылки на rvalue, определенно выглядит лучше, чем версия VS10, поскольку VS10 не имеет вариативных шаблонов и должен использовать ужасное черное искусство имитировать такое поведение. Но это полностью проблема времени компиляции, поэтому она не актуальна.

person Kerrek SB    schedule 24.06.2011
comment
Boost не ограничивается C ++ 98. Он использует функции C ++ 0x, такие как rvalues, если они доступны. Таким образом, в VC 10 используется идеальная семантика пересылки и перемещения и т. Д. См. boost.org/doc/libs/1_46_1/libs/smart_ptr/make_shared.html - person mpipe3; 24.06.2011
comment
@ mpipe3: Хорошо - реализация Boost в C ++ 0x, вероятно, очень похожа на VS10 в этом случае. Вы знаете, есть ли у Boost make_shared такая же эффективная реализация, как у VS10? - person Kerrek SB; 24.06.2011
comment
Я смущен. Вы говорите, что версия VS может быть быстрее или лучше? :-) - person liori; 24.06.2011
comment
@liori: Я не был уверен, насколько хорошо Boost использует новые возможности C ++ 0x. Похоже, что это так, поэтому они будут практически идентичны. Если вы заставляете Boost соответствовать C ++ 98, тогда VS10 должен иметь небольшое преимущество. - person Kerrek SB; 24.06.2011