Стоимость создания boost::shared_ptr по сравнению с вызовом boost::shared_ptr в unordered_map

Объявление «пользователей» в ServerData.h

    static std::unordered_map<long long, boost::shared_ptr<user_object>> users;

В чем разница в стоимости использования

    boost::shared_ptr<ServerData::user_object> user = ServerData::users[session.userid];
    session.name = user->name;//and approximately 20 other calls like this
    session.age = user->age;

и

    session.name = ServerData::users[session.userid]->name;
    session.age = ServerData::users[session.userid]->user->age;//and approximately 20 other calls like this.

Не могли бы вы дать ответы для рассмотрения двух различных сценариев, где:

1- ServerData::users.size() составляет от 100 до 10 КБ.

2- ServerData::users.size() больше 1M

users[session.userid] выполняет поиск каждый раз. Повторение этой строки — худший вид копипасты.
user7860670 12.02.2023 16:46

Не связанный с вопросом: зачем использовать boost::shared_ptr, если вы явно используете С++ 11 или более позднюю версию, в которой есть std::shared_ptr?

user17732522 12.02.2023 16:47

@ user17732522 Например, boost::shared_ptr может хранить указатели на массивы, которые стали доступны в std::shared_ptr только с C++17.

user7860670 12.02.2023 16:50

Если вы считаете, что поиск занимает линейное время в худшем случае, должно быть довольно ясно, какой из них предпочесть. Если вас беспокоит стоимость копирования shared_ptr, сделайте ссылку. Хотя причин для беспокойства по этому поводу нет.

molbdnilo 12.02.2023 16:57

Я неправильно прочитал изначально. Вас беспокоит, перевешивает ли стоимость копирования shared_ptr повторный поиск или какую стоимость вы пытаетесь здесь сравнить? Если это так, я бы сказал, что очень маловероятно, и этого можно избежать, сделав ссылку user в первом варианте.

user17732522 12.02.2023 16:57

@user17732522 user17732522 на самом деле я тоже не уверен в этом, единственная причина, по которой я его использую, заключается в том, что так много людей предлагали это, когда я впервые начал писать свой серверный код много лет назад. Очевидно, С++ 17 очень хорош, если бы я не использовал библиотеку asio от boost, я бы не использовал ее только для shared_ptr

ozan deniz 12.02.2023 17:09
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
64
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я не вижу никаких причин, чтобы предпочесть второе. Он ищет на карте каждую строку заново, что является дорогостоящей операцией. Это нужно только один раз.

Это должно быть верно независимо от размера карты, так как я не вижу почти никакой экономической выгоды во втором варианте вообще. Единственная дополнительная стоимость в первом варианте — это shared_ptr копия, которая не имеет значения для поиска по хеш-карте, и ее можно избежать, сделав user ссылку в первом варианте.

Да, я не был уверен в стоимости копирования shared_ptr, но получилось так, как я и ожидал. Спасибо за информацию.

ozan deniz 12.02.2023 17:06

@osandeniz «Я не был уверен в стоимости копирования shared_ptr» — почему вы не сказали об этом в вопросе? Вместо того, чтобы заставлять читателей выяснять, что вы видите в коде, вы должны быть явными. Например, «Какова разница в стоимости между созданием копии общего указателя с использованием» и «и поиском элемента карты каждый раз». Без дополнительного текста в вопросе я сомневаюсь, что другие с тем же вопросом смогут его найти.

JaMiT 13.02.2023 04:10

@JaMiT ты вообще читал заголовок? И я даже сказал в посте «разницу между использованием этих двух». Всегда не решаюсь спросить здесь из-за невыносимого количества вопросов, на которые я натыкаюсь каждый раз, когда задаю здесь вопрос. К счастью, другие были не такими, как ты.

ozan deniz 15.02.2023 22:49

@ozandeniz "ты вообще читал заголовок?" -- Заголовок? Я не вижу заголовка. Вы имеете в виду название вопроса? Если так, то да, я читал, но потом проигнорировал, потому что "вызов boost::shared_ptr" не имеет смысла. Я просто воздержался от этого, потому что это казалось бесполезным (и потому что у меня сложилось впечатление, что вы, возможно, не являетесь носителем английского языка). Однако, если вы действительно хотите причислить меня к «невыносимому меньшинству», я могу перейти в режим полной критики, указывая на каждую маленькую ошибку без каких-либо предложений по улучшению...

JaMiT 16.02.2023 02:12

@ozandeniz «Я даже сказал« разница между использованием этих 2 »» - не совсем. Вместо «этих 2» вы дали два блока кода для чтения (и никогда не упоминали «копировать»). Именно это я и предлагаю улучшить. Вместо «Какова разница в стоимости между использованием [кода] и [кода]» вы могли бы написать «Какова разница в стоимости между созданием копии общего указателя с использованием [кода] и поиском элемента карты каждый раз с использованием [ код]." Не полагайтесь на код для общения. Да, у вас слабая грамматика, но ваш английский все же более понятен, чем интерпретация кода.

JaMiT 16.02.2023 02:16

Вы можете просто измерять вещи — хотя в этом случае результаты очень предсказуемы:

Примечание:

На практике ваше приложение будет налагать ограничения. Например. повторный запрос карты может быть причиной гонки. Как и оптимизация для хранения ссылки вместо копирования общего указателя.

Например. используя Нониус:

#define NONIUS_RUNNER
#include <boost/make_shared.hpp>
#include <nonius/main.h++>
#include <random>

#include <boost/unordered_map.hpp>
#include <unordered_map>

using Id = long long;
static constexpr auto minId             = 1'000ll;
static constexpr auto maxId             = 2'000'000ll;
static constexpr auto numExtraFields    = 18u;
static auto const     fixed_random_seed = std::random_device{}();

static auto make_idgen() {
    return std::bind(std::uniform_int_distribution<Id>(minId, maxId),
                     std::mt19937{fixed_random_seed});
}

namespace ServerData {
    struct user_object {
        std::string name;
        unsigned    age;
        std::array<double, numExtraFields> more_fields;
    };
} // namespace ServerData

static auto const std_users = [] {
    std::unordered_map<long long, boost::shared_ptr<ServerData::user_object>> table;
    for (Id i = minId; i <= maxId; ++i)
        table.emplace(i, boost::make_shared<ServerData::user_object>("anonymous", 12));

    return table;
}();

NONIUS_BENCHMARK("hooboy", [](nonius::chronometer cm) {
    auto users = std_users;
    auto pick  = make_idgen();
    cm.measure([&] {
        auto id = pick();
        users[id]->name = "name";
        users[id]->age  = 12 + rand() % 30;
        for (size_t i = 0; i < numExtraFields; ++i)
            users[id]->more_fields[i] = i;
    });
});

NONIUS_BENCHMARK("reasonable", [](nonius::chronometer cm) {
    auto users = std_users;
    auto pick  = make_idgen();
    cm.measure([&] {
        auto sess = users[pick()];
        sess->name = "name";
        sess->age  = 12 + rand() % 30;
        for (size_t i = 0; i < numExtraFields; ++i)
            sess->more_fields[i] = i;
    });
});

NONIUS_BENCHMARK("optimizing", [](nonius::chronometer cm) {
    auto users = std_users;
    auto pick  = make_idgen();
    cm.measure([&] {
        auto& sess = *users[pick()];
        sess.name = "name";
        sess.age  = 12 + rand() % 30;
        for (size_t i = 0; i < numExtraFields; ++i)
            sess.more_fields[i] = i;
    });
});

static auto const boost_users = [] {
    boost::unordered_map<long long, boost::shared_ptr<ServerData::user_object>> table;
    for (Id i = minId; i <= maxId; ++i)
        table.emplace(i, boost::make_shared<ServerData::user_object>("anonymous", 12));

    return table;
}();

NONIUS_BENCHMARK("boost::unordered_map", [](nonius::chronometer cm) {
    auto users = boost_users;
    auto pick  = make_idgen();
    cm.measure([&] {
        auto& sess = *users[pick()];
        sess.name = "name";
        sess.age  = 12 + rand() % 30;
        for (size_t i = 0; i < numExtraFields; ++i)
            sess.more_fields[i] = i;
    });
});

Отпечатки

clock resolution: mean is 21.1389 ns (40960002 iterations)

benchmarking hooboy
collecting 100 samples, 45 iterations each, in estimated 2.1285 ms
mean: 700.709 ns, lb 693.765 ns, ub 710.277 ns, ci 0.95
std dev: 40.9973 ns, lb 32.3424 ns, ub 52.1336 ns, ci 0.95
found 16 outliers among 100 samples (16%)
variance is severely inflated by outliers

benchmarking reasonable
collecting 100 samples, 63 iterations each, in estimated 2.1294 ms
mean: 544.189 ns, lb 538.784 ns, ub 550.853 ns, ci 0.95
std dev: 30.5399 ns, lb 25.5757 ns, ub 37.0609 ns, ci 0.95
found 4 outliers among 100 samples (4%)
variance is severely inflated by outliers

benchmarking optimizing
collecting 100 samples, 65 iterations each, in estimated 2.1385 ms
mean: 535.605 ns, lb 529.619 ns, ub 543.946 ns, ci 0.95
std dev: 35.4216 ns, lb 27.9599 ns, ub 52.1946 ns, ci 0.95
found 3 outliers among 100 samples (3%)
variance is severely inflated by outliers

benchmarking boost::unordered_map
collecting 100 samples, 75 iterations each, in estimated 2.1075 ms
mean: 495.22 ns, lb 489.909 ns, ub 502.051 ns, ci 0.95
std dev: 30.7146 ns, lb 25.1169 ns, ub 37.8619 ns, ci 0.95
found 5 outliers among 100 samples (5%)
variance is severely inflated by outliers

Или в виде графика (нажмите для интерактивности):

Другие вопросы по теме