Pull to refresh
226
55.1
Antony Polukhin @antoshkka

Эксперт-разработчик C++ в Яндекс Go

Send message

Да, ranges ленивые и я походу тоже: в коменте справа я написал, что мы получим если пройдёмся по всем элементам диапазона и сохраним их куда-нибудь.

В примере везде используется std::get, который кидает исключение при попытке достать неверный тип. Замена на get_unsafe кардинально изменит поведение типа

В стандарте прописывается интерфнйс а не реализация. Слова "exposition only" в предложении не спроста стоят. Так что ничего не запрещает оптимизацию из abseil использовать в реализации стандартной библиотеки.

На operator*() никак std::variant не ложится, а std::visit покрывает большинство кейсов когда нужен непроверенный доступ. Если у вас другие кейсы и непровереный доступ вам нужен - пишите предложение для включения в стандарт, поможем с защитой идеи.

В комитете есть ребята из гугла, но они не торопятся предлагать подобное, а вместо этого голосуют по предложению expected. Может Status и StatusOr не так ужи и хороши?

Они базируются на рефлексии, а рефлексия окажется в лучшем случае в C++26. Так что пока ожидаем

Плохая поддержка в компиляторах - основной стоппер. Тот же Boost пока не внедрил модули, в частности потому что у большинства разработчиков на их машинах в компиляторах модули просто не работают.

Препроцессором такого не достичь:

int foo(int i) {
    switch (i) {
      case 42: return 64;
      case 142: return 6;
      case 1024: return 0;
    }
    // Без следующей строчки компилятор будет сыпать предупреждениями
    std::unreachable();
}

Их готовятся добавлять по кусочкам в стандарт. Например на подходе [[assume(x)]]

Все эти вещи успели проскочить нужные подгруппы и есть все шансы увидеть их в C++23

Хранить вторым аргументом исключение - это должно быть редким кейсом. Упор в std::expected сделан на хранение кодов ошибки - вы так получите тривиальность копирования expected, меньший размер объекта, более быструю передачу через регистры и т.п.

А вот кидать код ошибки - это очень сомнительное удовольствие, лучше уж кинуть что-то отнаследованное от std::exception, а именно bad_expected_access. Ну и ловить в коде тогда можно весьма ожидаемый std::exception, а например не srd::errc.

Что же касается operator* - в дебаге там будет assert, который поможет вам поймать проблему в тестах. В C++ operator* всегда является небезопасным доступом, и программист в ответе за проверку. Хотите чтобы стандартная библиотека делала проверку за вас - используйте value(). Если менять устоявшееся правило только для одного класса то будет только хуже - возникнет путанница.

Ну и наконец, это же C++. Не нравится стандартный std::expected - напишите и используйте свой, никто не заставляет пользоваться тем, что не подходит под ваши конкретные нужды.

Тип будет const char*

Фактически будем итерироваться по диапазону {"Hello", ", ", "world"}

Предложение на as/is было встречено положительно, но в C++23 pattern matching уже не попадёт. Моё предчувствие - идея пройдёт в стандарт C++26. А за прогрессом идеи можно наблюдать тут https://github.com/cplusplus/papers/issues/1064

А по второй идее предложение ещё не рассматривали. Но мне кажется, что шансы на принятие - минимальны

И сегодня как назло сломался сертификат для https://wg21.link/ . Ответственные предупреждены, скоро починят и ссылки на предложения заработают.

Всё так. Корутины и асинхронность - это не серебряная пуля для всех проблем, а лишь возможность экономить CPU на IO-bound приложениях.

В случае баз данных фреймворки зачастую предоставляют другие способы улучшить это место. Например userver использует бинарный протокол для общения с PostgreSQL (не тот, что по умолчанию в libpq), автоматическое превращение всех запросов в prepared statements, динамическое управление пулами; на подходе использование порталов и pipelining. Разумееется это всё полностью не убирает бутылочное горлышко, но позволяет его немного расширить

Проблема возникает на порядок раньше. У неё даже название есть - C10k, так что уже при подходе к 10к RPS вам нужен асинхронный движок (с корутинами или без).

В целом приблизительно всё так и дружится.

Но помимо интеграции с корутиновым движком нужны ещё метрики, логи, плагин для кодогенерации gRPC C++ кода, документация... В общем, работы на пару-тройку месяцев

Если все потоки яростно дерутся за общий ресурс то во всей красе проявляется закон Амдала:

Допустим 50% времени поток проводит в критической секции. Соответственно на системе с 100 ядрами вы получите ускорение 1÷(0.5 +(0.5÷100)) ~= 2. Всего в 2 раза быстрее будет работать ваш код на 100 ядерной машине, чем на одноядерной.

Ускорение мьютекса тут ситуацию не улучшит, нужно менять сам алгоритм, например использовать специальные очереди, так же предоставляемые фреймворком.

Если же в критической секции приложение проводит мало времени, то шансы столкновения сразу множества потоков на мьютексе малы и мы получаем картину из верхней части таблички. Со временем, мы наверное займёмся оптимизацией этого случая и сделаем некий backoff, но пока что это не в приоритете.

Это очень интересный вопрос.

В теории, так можно жить и даже можно сдлеать интересные оптимизации, экономящие CPU. Приблизительно так работает Python3, где основная часть программы однопоточная, а масштабирование происходит через запуск новых инстансов приложения.

На практике так жить зачастую не получается из-за несовершенства ОС (не для всего есть асинхронные вызовы) и из-за несовершенства драйверов к различным базам данных и протоколов передачи данных. В том же Python3 драйвер для gRPC порождает свой собственный поток.

С идеальным однопоточным режимом есть и недостаток - да, можно немного оптимальнее загрузить CPU, но страдает latency. Если к вам приходит запрос, обработку которого можно разложить на две несвязанные задачи по 400ms, то в однопоточном режиме вы вернёте ответ через 400ms+400ms. В многопоточном режиме задачи обработаются на разных потоках и ответ вы вернёте через 400ms.

Information

Rating
103-rd
Location
Россия
Works in
Registered
Activity