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

Так что мне бы очень хотелось увидеть тестирование скорости параллельных (например, от 100 до 10000 параллельных потоков), где каждый поток вставляет, находит, удаляет как минимум 3 типа одновременных карт - std :: map (с некоторыми мьютексы) против 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 Ответ

3 голосов
/ 28 августа 2011

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

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

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

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

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

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