Что быстрее на Visual C ++ 2010 - std :: shared_ptr или boost :: shared_ptr? - PullRequest
9 голосов
/ 24 июня 2011

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

Мне интересна скорость:

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

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

  3. Отменить ссылку на указатель для доступа к pointee

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

Ответы [ 2 ]

8 голосов
/ 27 июня 2011

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

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

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

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

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

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

Вот код Iб:

#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;
}

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

3 голосов
/ 24 июня 2011

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

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

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

...