Есть ли какой-нибудь тест скорости между "std::map with mutexes" и "libcds maps (Michael Hashmap и Split Order List)" "параллельной вставкой, поиском, стиранием?

Поэтому мне бы очень хотелось увидеть тестирование скорости параллельных (примерно от 100 до 10000 параллельных потоков), где каждый поток вставляет, находит, удаляет по крайней мере 3 типа одновременных карт - std::map (с некоторыми мьютексами) vs libcds (параллельные структуры данных)...

Так, например, если такого сравнения еще не существует, пожалуйста, помогите мне с его созданием.

Непосредственно связанные: LibCds: Michael Hashmap и Split Order List

Представь у нас

#include <iostream>
#include <boost/thread.hpp>
#include <map>

class TestDs 
{
public:

    virtual bool containsKey(int key)=0;
    virtual int get(int key)=0;
    virtual int put(int key, int value)=0;
    virtual int remove(int key)=0;

    virtual int size()=0;
    virtual const char* name()=0;
    virtual void print()=0;
    virtual void shutdown()=0;
};

class GeneralMap: public TestDs
{
private:

    std::map<int,int> _ds;
    mutable boost::mutex mut_;
public:
    GeneralMap() {}

    bool containsKey(int key) {
        boost::mutex::scoped_lock lock(mut_);
        if ( _ds.find(key) != _ds.end())
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    int get(int key) {
        boost::mutex::scoped_lock lock(mut_);
        return _ds[key];
    }

    int put(int key, int value) {
        boost::mutex::scoped_lock lock(mut_);
        _ds.insert(std::pair<int, int>(key,value));
        return key;
    }

    int remove(int key) {
        boost::mutex::scoped_lock lock(mut_);
        return _ds.erase(key);
    }

    int size() {
        boost::mutex::scoped_lock lock(mut_);
        return _ds.size();
    }
    const char* name() {
        return "StdMap";
    }
    void print() {}
    void shutdown() {}

};

чем создать такой тест, который бы создавал N потоков, и каждый поток вызывал бы создание, находил удаление... Я начал что-то писать, но теперь это скомпилированный код с boost 1.47.0...

#include <iostream>
#include <boost/thread.hpp>
#include <map>
#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/date_time.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random.hpp>
#include <boost/progress.hpp>

class timer 
{ 
public: 
    timer() : start_time_(boost::posix_time::microsec_clock::local_time()) {} 

    void restart() 
    {
        start_time_ = boost::posix_time::microsec_clock::local_time();
    } 

    boost::posix_time::time_duration elapsed() const 
    {
        return boost::posix_time::microsec_clock::local_time() - start_time_;
    } 
private: 
    boost::posix_time::ptime start_time_; 
};

class TestDs 
{
public:

    virtual bool containsKey(int key)=0;
    virtual int get(int key)=0;
    virtual int put(int key, int value)=0;
    virtual int remove(int key)=0;

    virtual int size()=0;
    virtual const char* name()=0;
    virtual void print()=0;
    virtual void shutdown()=0;
};

class GeneralMap: public TestDs
{
private:

    std::map<int,int> _ds;
    mutable boost::mutex mut_;
public:
    GeneralMap() {}

    bool containsKey(int key) {
        boost::mutex::scoped_lock lock(mut_);
        if ( _ds.find(key) != _ds.end())
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    int get(int key) {
        boost::mutex::scoped_lock lock(mut_);
        return _ds[key];
    }

    int put(int key, int value) {
        boost::mutex::scoped_lock lock(mut_);
        _ds.insert(std::pair<int, int>(key,value));
        return key;
    }

    int remove(int key) {
        boost::mutex::scoped_lock lock(mut_);
        return _ds.erase(key);
    }

    int size() {
        boost::mutex::scoped_lock lock(mut_);
        return _ds.size();
    }
    const char* name() {
        return "StdMap";
    }
    void print() {}
    void shutdown() {}

};

template <class map_wraper_t>
class test_map_wraper
{
public:

    test_map_wraper(int threads_number)
    {
        n = threads_number;
    }

    void start_tests()
    {

        boost::upgrade_lock<boost::shared_mutex> lock(tests);
        boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);

        boost::shared_lock<boost::shared_mutex> lock_r(results);

        for(int i=0; i<n; i++)
        {
            boost::thread worker(&test_map_wraper::test, this, i);
        }
        boost::thread worker_r(&test_map_wraper::result, this);
        timerForCaptureFame.restart();
    }
private:
    int n;
    boost::shared_mutex  tests;
    boost::shared_mutex  results;
    boost::random::mt19937 rng;
    timer timerForCaptureFame;
    map_wraper_t Ds;
    boost::progress_display *show_progress;

    void test( int i)
    {
        boost::shared_lock<boost::shared_mutex> lock_r(results);
        boost::shared_lock<boost::shared_mutex> lock(tests);
        Ds.put(i, 0);
        if (Ds.containsKey(i))
        {
            Ds.get(i);
        }
        Ds.remove(i);
    }

    void result()
    {
        boost::upgrade_lock<boost::shared_mutex> lock(results);
        boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);

        std::cout <<  std::endl << "test of " << Ds.name() << " complite;" << std::endl << "test performed on " << n << " items" << std::endl << "test duration: " << timerForCaptureFame.elapsed() << std::endl;
    }
};


int main()
{
    int threads_n = 1000;
    int tests = 5;
    std::cout << "Number of required tests: " << tests << std::endl << "Number of threads in each test: " << threads_n << std::endl << "Wait for it..." << std::endl;
    //for(int i = 0; i < tests; ++i)
    //{
        test_map_wraper<GeneralMap> GeneralMapTest(threads_n);
        GeneralMapTest.start_tests();
    //}
    std::cin.get();
    return 0;
}

1 ответ

Решение

Да, это в модульных тестах для LibCds

Он будет запускать те же тестовые сценарии со всеми видами карт различных типов, включая реализации без блокировок, но также std::map/set с блокировками и без них.

Конечно, никакая синхронизация явно не является победителем, но она не будет работать, когда в миксе есть писатели. Реализации без блокировок выходят намного быстрее, чем контейнеры STL с синхронизированным доступом.

Все это не должно быть сюрпризом. Почему ты спрашиваешь?

PS. модульный тест здесь:

  • получить тар мяч
  • экстракт
  • построить (cd build && ./build.sh)
  • модульные тесты в ./bin/*/cds-unit или же ./bin/*/cds-unit-debug если построен с --debug-test
Другие вопросы по тегам