boost::shared_mutex медленнее, чем грубый std::mutex в Linux
У меня есть std::unordered_map
которая подвергается очень большой нагрузке на чтение из нескольких потоков. Я мог бы использовать std::mutex
для синхронизации, но так как одновременное чтение должно быть в порядке, я хотел использовать boost::shared_mutex
вместо. Чтобы проверить улучшение производительности, я предварительно заполняю карту набором значений, а затем несколько потоков запускаю тест на чтение:
for (int i = 0; i < iters; ++i) map.count(random_uint(0, key_max));
Я запускаю это для моей грубой блокировки реализации, где count
защищен std::lock_guard<std::mutex>
и для моей реализации разделяемой блокировки, где он защищен boost::shared_lock<boost::shared_mutex>
,
В моей системе Arch Linux x86_64 с GCC 6.1.1 boost::shared_lock
версия всегда медленнее! В системе моего друга Windows 10 с MSVC 2013 boost::shared_lock
всегда быстрее! Полный, компилируемый код находится на github: https://github.com/silverhammermba/sanity
редактировать
Кажется, это проблема для конкретной платформы. Смотри выше. Я был бы очень признателен, если бы кто-нибудь еще мог собрать и запустить этот код и сообщить, видел ли он положительный результат (shared_lock
быстрее) или отрицательно (конечно, мьютекс быстрее) и какую платформу вы используете.
2 ответа
Оказывается, что boost::shared_mutex
является "неоптимальным" в Linux.
Текущая (с бустом 1.59) реализация boost::shared_mutex для 'pthread' довольно неоптимальна, так как она использует тяжеловесный мьютекс для защиты состояния внутреннего мьютекса... [когда параллелизм доступа высок) общий мьютекс эффективно исключает.
Ура для повышения и много часов моей жизни, которые он украл.
Несколько заметок:
Если ваша структура данных страдает от высокой конкуренции, настоятельно рекомендуется использовать ту же структуру данных с реализацией без блокировки
Блокировки Reader-Writer обычно приносят повышение производительности, когда чтения являются общими, но записи происходят редко. С философской точки зрения, если блокировка должна определить, захватила ли другая нить блокировку либо в режиме чтения, либо в режиме записи, это медленнее, чем простое ожидание снятия блокировки. Таким образом, если чтения являются общими, а записи редкими, другие потоки не блокируются. Если записи являются общими, блокируются не только потоки, но они должны выполнять дополнительную логику, чтобы выяснить, как что блокирует.
Итак, на лету, ваши примеры неправильно используют блокировку. А также используйте программирование без блокировок, если производительность вас устраивает.