Сишники вполне себе обращаются с void, но почему-то все становится плохо, когда эту идею пытаются развить и строго объяснить с позиции системы типов и идеологии языка.
Поподробнее об этом, пожалуйста. Что именно становится плохо?
Вероятно потому, что с void сишник знакомится в младенчестве и просто принимает на веру
Некой мистической «строгостью» понимание не ограничено, логика не ограничена.
«надо писать void, когда функция не возвращает значения, а void* это… ну просто указатель, когда не знаем, на что указываем»
А ещё надо писать void, когда функция не принимает аргументов. Давайте поиграем в игру.
void определяет отсутствие результата, либо возврата. Как хотите это называйте. Что такое тип у указателя? Это тип возвращаемого операцией разыменования значения.
Что такое void * — это указатель для которого нет операции разыменования. *(void *) == void, то же самое что void f() {}; f(). Результата нет.
Мы не не знаем на что указываем — мы ни на что не указываем. «указатель указывает» — это детский садик. Это как функция у которой нельзя взять результат, так это — указатель, у которого так же нельзя взять результат.
int f(); и int * p; — они идентичны. Только у одной операция скобочки, а у второй звёздочка.
Тут скорее всего проблема в том, что как и сишник принимает на веру — так и представления о си — это вера. И то, что у кого-то есть вера — из этого не следует то, что без веры в си нет логики.
Изначально было про то, что сишные функции для работы со строками в рамках std::string не применимы по причине отсутствия нуля после ресайза. Я доказал, что это не так.
Далее я помог автору комментария и привёл реальный пример( валидный для std::string), но невалидный для сишных строк. Вы зачем-то пришли и повторили мне то, что я итак сказал до вас. Зачем?
А теперь играете в игру «игнорирую всё» — зачем?
Если вы хотите нулевые символы в строке, то вам неизбежно придётся таскать рядом размер этой строки.
Зачем мне нулевые символы? Ну хорошо — придётся таскать, и?
Это отменяет что-то ранее сказанное мною, либо противоречит чему-то? Это ответ на моё утверждение намного выше?
Длинны в С++-строке это просто некая оптимизация получения длинные и не более того.
Это? Ну дак надо отвечать на тот комментарий, а не на другой.
Да и как я уже сказал — нулевые символы это больше надуманный кейс, чем реальный. От того я его и не рассматриваю. Если хотите — пусть будет length ещё и для хранения нулевых символов. Сломается ::data(), ::c_str(), но что поделать.
Это неважно. Вы отвечаете в том контексте, которые определили до(после вас) вас. В нём же отвечал и я. Менять условия нельзя.
Мой тезис был такой — epoll(0) это хак. И конечно это хак! Смотрите — одно и то же решение: 43 место без epoll(0), 7 с epoll(0), изменена одна строка в коде!
Ну дак перечитайте то — на что я отвечал и кому. Зачем менять условия?
Вам не нравится одна строчка? Ну что поделать.
Это по вашему филигранная работа и особенности? Мдмашка в чистом виде.
Это не работа — это знание особенной того окружения, в котором работаете.
Тут и комментировать нечего. Конечно применимы, в реальных хайлод все это сплошь и рядом.
Тогда это решение точно так же применимо в хайлоаде. Профит даёт.
Ну и не понятно так же. Всё это соответствует критериям, которые определили выше. И определил их не я. Вы точно так же оспорили это: habrahabr.ru/post/338268/#comment_10428330
В чём причина ваших ко мне претензий?
Во всех где вызываешь epoll(0) (а это все ядра, иначе зачем он вам вообще нужен в любом виде в реальном проде?).
Епул не обязательно долбить из всех потоков.
Из личного опыта знаю, что когда все ядра заняты на 100% (а именно это происходит) доступ по ssh становится невозможным.
Не знаю что там у вас за опыт, но такого не может быть по определению. Да и мой опыт говорит прямо об обратном.
Даже на десктопе я могу пустить этот вайлтру в скольки угодно тредах и это мне не помешает не то что по ssh зайти, а смотреть ютуб и писать на хабре. При этом это полностью стоковое ядро.
И вообще вы какой-то нервенный… Судя по нику — из-за расклада с PHP в highloadcup-е? Ну так там и нода утерлась, не переживайте вы так.
Я, неверное, непонятно и глупо ответил. Чтобы подобно не повторялось — дополню.
Дело в том, что отвечающий в ответе на мой комментарий описал ту ситуацию, которая уже была описана мною в том комментарии, на который он, собственно, и ответил.
С точки зрения сожжения CPU — безусловно и epoll(0) и пхп с jvm жгут его с КПД разной степени паршивости.
Это не ответ. Было определено два тезиса: «Потому что в реальных», «а напрасное пережигание электричества».
Что из этого следует? А то, что всё что не из множества «реальных задач» и всё, что «напрасно пережигает электричество» неприменимо и является хаком.
Мною были выдвинуты контрпримеры — на что последовало молчания. Если не можете в аргументацию своих тезисов, то зачем это вообще начинать?
я представляю решение на пхп в проде
Опять же. Вы нарушаете условие. Применимы-ли в проде парсинг жсона и хттп так, как это сделано в некоторых(почти всех) решениях? Нет. Ну дак зачем вы суёте сюда то, чем решения заведомо не соответствует.
Так же, не важно то, что вы представляете, а что нет. Пхп просто так жрёт электричество? Жрёт. Под критерий определённый автором первоначального утверждения подходит? Подходит. Всё остальное — отношения к делу не имеет.
Вы можете начать рассуждать о том, что рабсила дороже электричества, как какие-то иные критерии дороже, но. За это решение покупается производительность. Точно так же, как в пхп покупается что-то другое.
Никто не определил, что производительность — это «неважный» критерий, а что-то иное важный.
но с epoll(0) уже нет, даже банально по ssh туда влезть не удастся.
Не верно. Епул долбит не во всех потоках одновременно, а даже если во всех — есть планировщик. Никакой ссш у вас не сломается.
Ну и вообще, кто вас сказал о том, что epoll(0) заканчивается на захардкоренном нуле? Ничего вам не мешает считать время проведённое в обработчике и на основе данной статистике рулить этим аргументом.
Я не минусил (и не умею ;)
Я говорю не про вас, а про тех, кто минусует без аргументации.
Кто смелый — кто сможет аргументировать за минусы? А то получается странно. Минусы есть, а ответов нет. В такой ситуации ведь не скажешь, что «я просто несогласен, а ответ уже итак дан другим участником и я с ним согласен». Почему вы поступаете так несправедливо?
Память в современном, да и в любом другом мире, не отделима от CPU. ЦПУ читает память и время затраченное на её чтение/запись/ожидание прямо пропорционально кол-ву этой самой памяти, при прочих равных. А они равные.
Главная проблема GC не в том, что оно вносит задержки
Задержки стоят ЦПУ, внезапно. Сколько их — одна большая, либо много маленьких — неважно. Хотя много — естественно дороже.
А jvm — это не напрасное прожигание электричества? А пхп — это не напрасное прожигание электричества? А жсон, хттп и прочее — это что? Это такое же напрасное прожигание электричества.
Ведь вы же измеряли цпу-время разных решений, да и в реальном мире производительность любых решений покупается в основном за счёт электричества и железа.
А подобные кастыльные парсеры жсона так же используются в реальных задачах? А подобные роутеры так же используются в реальных задачах? Что же вы так избирательны.
Я не знаю причины по которым вы говорите то, что говорите. Но я предполагаю то, что причина тут явно не в реальных задачах, не в электричестве, а в неком недовольстве/обиде на тех, кто этот «хак» знал.
Это ложная уверенность, а любая ложная уверенность способствует большему кол-во ошибок, нежели что-то иное.
А если попробует записать что-то в nullptr, то это сразу будет видно.
В этом вся суть — мы взяли какой-то кейс и выдали его за все косяки, либо за какую-то весомую их часть. Это не так.
Разименование адреса «на прямую» достаточно редкий кейс, особенно в современном С++. new через new — уже не модно — это не жава.
Нулевой this вызывать функции позволяет, любые поля, кроме нулевого — будут не nullptr(скорее всего оно попадёт в нулевую страницу, но это просто особенность модели памяти и вас тут просто повезло, ведь вы говорили о nullptr). Все филды после 4к — уже мимо. Массивы — мимо.
Плюс, есть много кейсов, где это только навредит. Получили в оффсет ноль — не получили сегфолт, а получили мусор — получили сегфолт.
struct{arr[10];}.arr[offset] = 123;
На самом деле в любой программе используется малая часть адресспейса. Сколько там там памяти на топовой ноде? Одна миллиардная доля? Даже если это мы заммапим сотни петабайт — это копейки. Это даже не один процент.
Исходя из всего этого шанс разименовывая мусор попасть не на сегфолт достаточно туманны.
Вы начали с того, что топовое решение на Rust попало только на 31-е место, а вот на Go — аж на 15-е (потом поправили что на 11-е).
Это был не я.
Просто уточню, что решение на Rust (раз уж за него зацепились) отставало от 1-го места по очкам менее чем вдвое. И именно в этом контексте я и написал, что в таких условиях решает не язык, а конкретные оптимизации.
Именно про это я и говорю, но. Конкретные оптимизации зависят от языка и я, так же, сказал почему.
Я спорю именно с тем, что оптимизации — это какая-то вещь в себе. Нет. Для оптимизаций нужны возможности, в том числе, со стороны языка.
Точно так же, как выбор языка не делается просто так. Он обусловлен той областью, в которой работает человек. Т.е. язык косвенно влияет и на опыт человека и на его компетенцию в данной теме.
Плюс — хайлоад кап был чисто русский, так что могло быть просто мало народу в русскоязычном комьюнити.
Очень много. По крайней мере агитаторов.
Я например узнал о соревновании сильно постфактум.
Аналогично. Странно, что организаторы для такой холиварной темы не оставили рабочей свою систему проверки решений и рейтинг(вне зачёта) активным на месяц. Многие(в частности, тут мелька ссылка на редит, где раст-участник жаловался на недостаток времени) просто не успели.
Дело было в placement new, который в C++ вызывает конструирование объекта. А конструирование объекта, это инициализация.
Дело было не в этом. Зачем обманывать?
Был определён кейс «выделить память и инициализировать», допустим — инициализировать очередь для обработки. На самом деле даже это неважно — просто инициализировать память.
В языка с ГЦ память будет проинициализирована ДВА раза. В С++ один раз. Плюс, ещё остаётся открытый вопрос о том, можно ли вообще аллоцировать массив за одну аллокацию.
Только в C++ строки это контейнер
Строк в С++ нет, как и в си. Есть std::string, но строки на нём не заканчиваются. Даже если поверить в то, что строки есть, так же в С++ есть сроки из си. С какой стороны не взгляни — утверждение неверное.
у которого есть lenght и capacity. И если хочу «очистить строку», то сбрасываю длину.
И что же из этого следует? Какое отношение это имеет к моей цитате? Это её опровергает, либо что?
*str = 0; Имеет ту же семантику. Дальше что? std::string, кстати, делает то же самое — сишное *str = 0, только к этому изменяет ещё size.
И алгоритмы оперирующие на длину, а не на нуль символ, как работали так и работают.
Начнём с того, что ничего не запрещает std::string изменять «нуль-символ». Т.к. в крестах нет реаллока, а у c_str() сложность константная, то срока обязана иметь капасити +1 для нуля. Уже давно даже data() нуль-терминированная.
Таким образом через что не возьми данные из std::string — сишные функции работать будут. Тут вы соврали.
Если вы хотели привести контр-пример, то надо было приводить нуль-символы в строке. Но опять же есть memchr(), memcpy().
Поэтому да же в программах на Си, можно увидеть свою реализацию строк.
Поэтому — это почему? Из-за lenght у std::string в С++? Сомневаюсь. Поэтому явно от С++ не зависит.
А оптимизацию для lenght можно прикрутить к чему угодно. И из этого мало что следует.
Велосипеды-обёртки поверх сишных строк строками не являются.
И кроме как embedded это особо никому не нужно, т.к. можно исользовать пул объектов.
Не можно. Это раз, а два — к чему ваши оценки? Вы говорили о чём? О том, что можно делать то же самое, а теперь вы пытаетесь избавиться от неудобных примеров оптимизаций.
Ну и голословные утверждения про «не нужно» вы так же чем-то сможете подтвердить?
Какой-нибудь memset с 0.
Это не очищение памяти. И с по каким таким причинам она вдруг должна «очищаться»?
Дело в том, что память и объекты — это разные вещи. Объекты могут и обычно несут в себе какую-то логику инициализации. Память же — это просто память.
Сишниые строки в самом C/C++ редко использую, т.к. strlen пробегает по всей строке и это медленно.
Сишные строки как раз-таки и используются. Длинны в С++-строке это просто некая оптимизация получения длинные и не более того.
Есть всякие поиски подстрок, поиски символов и прочее. А медленно — это только в кейсе получения длинны. Остальные операции со строками требует прохода по ней и проверка символа на ноль — операция с нулей(в большинстве случаев) стоимостью. Какая разница что делать — сравнивать два указателя, либо сравнивать текущий символ с нулём?
А в C++ не так?
Да, в С++ это не так. Можно выделить кусок памяти не создавая объектов, а потом создать их в уже выделенной памяти во время её обхода.
В критичных местах в C++ да же предварительно не очищается память, просто помечаем как «свободную».
Что понимается под «очищением памяти»? Возврат страниц в систему? Подобное поведение свойственно любым менеджерам памяти. В реализации почти всех языков берут какой-нибудь jmalloc/tcmalloc/gnumallo, либо свой велосипед. Поэтому менеджер памяти в других языках не обладает какими-то резко другими свойствами.
Поподробнее об этом, пожалуйста. Что именно становится плохо?
Некой мистической «строгостью» понимание не ограничено, логика не ограничена.
А ещё надо писать void, когда функция не принимает аргументов. Давайте поиграем в игру.
void определяет отсутствие результата, либо возврата. Как хотите это называйте. Что такое тип у указателя? Это тип возвращаемого операцией разыменования значения.
Что такое void * — это указатель для которого нет операции разыменования. *(void *) == void, то же самое что void f() {}; f(). Результата нет.
Мы не не знаем на что указываем — мы ни на что не указываем. «указатель указывает» — это детский садик. Это как функция у которой нельзя взять результат, так это — указатель, у которого так же нельзя взять результат.
int f(); и int * p; — они идентичны. Только у одной операция скобочки, а у второй звёздочка.
Тут скорее всего проблема в том, что как и сишник принимает на веру — так и представления о си — это вера. И то, что у кого-то есть вера — из этого не следует то, что без веры в си нет логики.
Я знаю о том, что произойдёт при epoll(0). Хотя формулировка не верна — кол-во событий на ожидание не влияет — любой событие будет епул.
Кому? Дяди Васи? Что конкурирует с епуллом по ЦПУ? Неужели обработчик евентов в том же треде(как это делается во всех реализация, что я видел)?
Какие ваши доказательства?
Сломается — это будет совсем не строка, что ожидается.
Изначально было про то, что сишные функции для работы со строками в рамках std::string не применимы по причине отсутствия нуля после ресайза. Я доказал, что это не так.
Далее я помог автору комментария и привёл реальный пример( валидный для std::string), но невалидный для сишных строк. Вы зачем-то пришли и повторили мне то, что я итак сказал до вас. Зачем?
А теперь играете в игру «игнорирую всё» — зачем?
Зачем мне нулевые символы? Ну хорошо — придётся таскать, и?
Это отменяет что-то ранее сказанное мною, либо противоречит чему-то? Это ответ на моё утверждение намного выше?
Это? Ну дак надо отвечать на тот комментарий, а не на другой.
Да и как я уже сказал — нулевые символы это больше надуманный кейс, чем реальный. От того я его и не рассматриваю. Если хотите — пусть будет length ещё и для хранения нулевых символов. Сломается ::data(), ::c_str(), но что поделать.
Это неважно. Вы отвечаете в том контексте, которые определили до(после вас) вас. В нём же отвечал и я. Менять условия нельзя.
Ну дак перечитайте то — на что я отвечал и кому. Зачем менять условия?
Вам не нравится одна строчка? Ну что поделать.
Это не работа — это знание особенной того окружения, в котором работаете.
Тогда это решение точно так же применимо в хайлоаде. Профит даёт.
Ну и не понятно так же. Всё это соответствует критериям, которые определили выше. И определил их не я. Вы точно так же оспорили это: habrahabr.ru/post/338268/#comment_10428330
В чём причина ваших ко мне претензий?
Епул не обязательно долбить из всех потоков.
Не знаю что там у вас за опыт, но такого не может быть по определению. Да и мой опыт говорит прямо об обратном.
Даже на десктопе я могу пустить этот вайлтру в скольки угодно тредах и это мне не помешает не то что по ssh зайти, а смотреть ютуб и писать на хабре. При этом это полностью стоковое ядро.
Не из-за этого. Я уже описал причины.
Дело в том, что отвечающий в ответе на мой комментарий описал ту ситуацию, которая уже была описана мною в том комментарии, на который он, собственно, и ответил.
Это не ответ. Было определено два тезиса: «Потому что в реальных», «а напрасное пережигание электричества».
Что из этого следует? А то, что всё что не из множества «реальных задач» и всё, что «напрасно пережигает электричество» неприменимо и является хаком.
Мною были выдвинуты контрпримеры — на что последовало молчания. Если не можете в аргументацию своих тезисов, то зачем это вообще начинать?
Опять же. Вы нарушаете условие. Применимы-ли в проде парсинг жсона и хттп так, как это сделано в некоторых(почти всех) решениях? Нет. Ну дак зачем вы суёте сюда то, чем решения заведомо не соответствует.
Так же, не важно то, что вы представляете, а что нет. Пхп просто так жрёт электричество? Жрёт. Под критерий определённый автором первоначального утверждения подходит? Подходит. Всё остальное — отношения к делу не имеет.
Вы можете начать рассуждать о том, что рабсила дороже электричества, как какие-то иные критерии дороже, но. За это решение покупается производительность. Точно так же, как в пхп покупается что-то другое.
Никто не определил, что производительность — это «неважный» критерий, а что-то иное важный.
Не верно. Епул долбит не во всех потоках одновременно, а даже если во всех — есть планировщик. Никакой ссш у вас не сломается.
Ну и вообще, кто вас сказал о том, что epoll(0) заканчивается на захардкоренном нуле? Ничего вам не мешает считать время проведённое в обработчике и на основе данной статистике рулить этим аргументом.
Я говорю не про вас, а про тех, кто минусует без аргументации.
Память в современном, да и в любом другом мире, не отделима от CPU. ЦПУ читает память и время затраченное на её чтение/запись/ожидание прямо пропорционально кол-ву этой самой памяти, при прочих равных. А они равные.
Задержки стоят ЦПУ, внезапно. Сколько их — одна большая, либо много маленьких — неважно. Хотя много — естественно дороже.
Это что такое?
Ведь вы же НЕ измеряли цпу-время разных решений. Естественно.
Ведь вы же измеряли цпу-время разных решений, да и в реальном мире производительность любых решений покупается в основном за счёт электричества и железа.
А подобные кастыльные парсеры жсона так же используются в реальных задачах? А подобные роутеры так же используются в реальных задачах? Что же вы так избирательны.
Я не знаю причины по которым вы говорите то, что говорите. Но я предполагаю то, что причина тут явно не в реальных задачах, не в электричестве, а в неком недовольстве/обиде на тех, кто этот «хак» знал.
Это ложная уверенность, а любая ложная уверенность способствует большему кол-во ошибок, нежели что-то иное.
В этом вся суть — мы взяли какой-то кейс и выдали его за все косяки, либо за какую-то весомую их часть. Это не так.
Разименование адреса «на прямую» достаточно редкий кейс, особенно в современном С++. new через new — уже не модно — это не жава.
Нулевой this вызывать функции позволяет, любые поля, кроме нулевого — будут не nullptr(скорее всего оно попадёт в нулевую страницу, но это просто особенность модели памяти и вас тут просто повезло, ведь вы говорили о nullptr). Все филды после 4к — уже мимо. Массивы — мимо.
Плюс, есть много кейсов, где это только навредит. Получили в оффсет ноль — не получили сегфолт, а получили мусор — получили сегфолт.
На самом деле в любой программе используется малая часть адресспейса. Сколько там там памяти на топовой ноде? Одна миллиардная доля? Даже если это мы заммапим сотни петабайт — это копейки. Это даже не один процент.
Исходя из всего этого шанс разименовывая мусор попасть не на сегфолт достаточно туманны.
Почему же хаки? Знание и использование особенностей работы.
Это был не я.
Именно про это я и говорю, но. Конкретные оптимизации зависят от языка и я, так же, сказал почему.
Я спорю именно с тем, что оптимизации — это какая-то вещь в себе. Нет. Для оптимизаций нужны возможности, в том числе, со стороны языка.
Точно так же, как выбор языка не делается просто так. Он обусловлен той областью, в которой работает человек. Т.е. язык косвенно влияет и на опыт человека и на его компетенцию в данной теме.
Очень много. По крайней мере агитаторов.
Аналогично. Странно, что организаторы для такой холиварной темы не оставили рабочей свою систему проверки решений и рейтинг(вне зачёта) активным на месяц. Многие(в частности, тут мелька ссылка на редит, где раст-участник жаловался на недостаток времени) просто не успели.
Дело было не в этом. Зачем обманывать?
Был определён кейс «выделить память и инициализировать», допустим — инициализировать очередь для обработки. На самом деле даже это неважно — просто инициализировать память.
В языка с ГЦ память будет проинициализирована ДВА раза. В С++ один раз. Плюс, ещё остаётся открытый вопрос о том, можно ли вообще аллоцировать массив за одну аллокацию.
Строк в С++ нет, как и в си. Есть std::string, но строки на нём не заканчиваются. Даже если поверить в то, что строки есть, так же в С++ есть сроки из си. С какой стороны не взгляни — утверждение неверное.
И что же из этого следует? Какое отношение это имеет к моей цитате? Это её опровергает, либо что?
*str = 0; Имеет ту же семантику. Дальше что? std::string, кстати, делает то же самое — сишное *str = 0, только к этому изменяет ещё size.
Начнём с того, что ничего не запрещает std::string изменять «нуль-символ». Т.к. в крестах нет реаллока, а у c_str() сложность константная, то срока обязана иметь капасити +1 для нуля. Уже давно даже data() нуль-терминированная.
Таким образом через что не возьми данные из std::string — сишные функции работать будут. Тут вы соврали.
Если вы хотели привести контр-пример, то надо было приводить нуль-символы в строке. Но опять же есть memchr(), memcpy().
Поэтому — это почему? Из-за lenght у std::string в С++? Сомневаюсь. Поэтому явно от С++ не зависит.
А оптимизацию для lenght можно прикрутить к чему угодно. И из этого мало что следует.
Велосипеды-обёртки поверх сишных строк строками не являются.
Не можно. Это раз, а два — к чему ваши оценки? Вы говорили о чём? О том, что можно делать то же самое, а теперь вы пытаетесь избавиться от неудобных примеров оптимизаций.
Ну и голословные утверждения про «не нужно» вы так же чем-то сможете подтвердить?
Это не очищение памяти. И с по каким таким причинам она вдруг должна «очищаться»?
Дело в том, что память и объекты — это разные вещи. Объекты могут и обычно несут в себе какую-то логику инициализации. Память же — это просто память.
Сишные строки как раз-таки и используются. Длинны в С++-строке это просто некая оптимизация получения длинные и не более того.
Есть всякие поиски подстрок, поиски символов и прочее. А медленно — это только в кейсе получения длинны. Остальные операции со строками требует прохода по ней и проверка символа на ноль — операция с нулей(в большинстве случаев) стоимостью. Какая разница что делать — сравнивать два указателя, либо сравнивать текущий символ с нулём?
Да, в С++ это не так. Можно выделить кусок памяти не создавая объектов, а потом создать их в уже выделенной памяти во время её обхода.
Что понимается под «очищением памяти»? Возврат страниц в систему? Подобное поведение свойственно любым менеджерам памяти. В реализации почти всех языков берут какой-нибудь jmalloc/tcmalloc/gnumallo, либо свой велосипед. Поэтому менеджер памяти в других языках не обладает какими-то резко другими свойствами.