Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Но мы ведь знаем, что все эти теории — ерунда, и рано или поздно, а скорее всего циклов через 80, шарик обязательно попадёт в эту единственную клетку.
std::vector задействовать std::list, то реаллоцировать массив и не придется…Поиск элемента по номеру (вернее, пролистывание k элементов по цепочке) — операция несопоставимо более быстраяЭто с какого-такого перепугу?100 ns (грубо), а чтение мегабайта — 250,000 ns (тоже грубо), то есть фактически вам всё равно — читать из памяти один байт или байт 300-400. Сколько там у нас данных хранится для одной карты? Один байт? Да пусть даже и десять, всё равно std::list проиграет.1. Выделить память под n+1Это зачем такой ужас-то?
2. Скопировать k-1 и еще n-k элементов
erase в std::list память не реаллоцирует и копирует только «хвостовые элементы». В среднем — тоже половину, только для реализации на базе std::listа «плохие» варианты — когда карта ближе к концу, а для для реализации на базе std::vectorа — когда ближе к началу.Учитывая, что удалять элемент придется при каждом доступе, этот вариант наверняка быстрее.s/быстрее/медленнее/
std::listа — это просто «умри всё живое»: там с неизбежностью придётся оперировать гигантскими структурами, что будет весьма медленно. Если же у нас странная колода с миллионом карт, то там, конечно, время аллокации/деаллокации станет незаметным, но проблемы со скоростью доступа к памяти никуда не денутся.std::list — требуй бенчмарков. В 90% случаев это обозначает, что человек не понимает что делает и на самом деле тут нужен либо std::vector, либо std::unordered_set, либо, редко, std::set. Задачи, для которых std::list оптимален встречаются примерно также часто как солнечные затмения. Они легко придумываются, но редко встречаются на практике.чтение из памяти занимает 100 ns (грубо), а чтение мегабайта — 250,000 ns (тоже грубо), то есть фактически вам всё равно — читать из памяти один байт или байт 300-400
Это зачем такой ужас-то? erase в std::list
При удалении карты из массива память не высвобождается, нужно всего-навсего сдвинуть данные о не более, чем о 51й карте. По сравнению с этим высвобождение памяти, которое неизбежно последует за удалением элемента из std::listа — это просто «умри всё живое»
nop. Скорее всего она сведется к выкидыванию указателя из таблицы аллокации — и всё. Хотя опять же, утверждать ничего не буду — в подобных случаях предпочитаю обычно не теоретизировать, а измерять. А в конкретном случае вообще спорить не о чем — потери в любом случае ерундовые. Зря я вообще эту дискуссию начал…Раз уж вы начинаете разговор про оптимизацию, то учтите, пожалуйста, что так как изначальный список будет выделяться, скорее всего, за один прием, а размер кеша процессора намного длиннее, то скорее всего весь список целиком провалится в кеш.Только в том случае если ваша программа ничем, кроме тасования карт не занимается. Да и в этом случае вариант с вектором будет быстрее, просто выигрыш будет не ~10-15 раз, а где-то 1.5-2 раза. Не любят современные системы рандомного доступа от слова «совсем». Только кеш первого уровня их нормально обслуживает, но там мизер — от 16KiB до 64KiB даже на самых новейших процессорах. Оттуда и код и данные «вылетают» очень быстро.
Не в list, а в vector, который предлагал предыдущий оратор. Я как раз и утверждаю, что удалить элемент из середины вектора много дольше, чем искать по листу.Это я опечатался. Конечно речь идёт о
erase в std::vectorе. Это он аллокациями не занимается и перемещает только «хвост» массива, как я описал. erase в std::listе ничего никуда не двигает, понятно, но платит за это слишком большую цену.Тут, пожалуй, соглашусь… хотя подзреваю, что освобождение 20 байтов из страницы, принадлежащей приложению, — это операция чуть более сложная, чем nop.И да и нет. Вам в любом случае нужно простись где-то по 3-5 указателям в среднем (иногда больше в зависимости от того как аллокатор сделан), что, понятно, копейки, но обращение к массиву объёмом в ~50 байт — всё равно стоит много дешевле.std::list со всеми его накладными расходами. Потому что иногда инструкции нужно вставлять в середину списка и удалять оттуда. Но оказалось, что std::vector потому что просто меньше памяти расходует, а то, что вставление/удаление элементов стоит «дорого» оказалось неважно. И это — типичный случай. Проблема в том, что в случае, когда работа устроена как «пройтись по std::listы, подёргать пару элементов», то std::vector, как правило, выигрывает: пройтись по нему быстрее, а что «подёргать пару элеменов» — это уже не так важно! Выигрыш std::list даёт тогда, когда вы имеете огромный список с которым работаете локально — то есть не просматриваете весь список (или его существенную часть), а обрабатываете как-нибудь хитро близко расположенные элементы. Это, вообще говоря, редко случается.std::listа. Не то, что он никогда не может быть нужен, но в 9 случаях из 10 его использование — ошибка проектирования системы.Ведь если останется всего одна последняя клетка, кто знает, сколько раз придётся повторяться? Сколько времени понадобится 16-битному процессору, чтобы выполнить столько циклов?
function genExtRandID() {
global $cfg;
// We can allow collissions...extId and email must be unique ...so same id with diff emails is ok..
// But for clarity...we are going to make sure it is unique.
$id=Misc::randNumber(EXT_TICKET_ID_LEN);
if(db_num_rows(db_query('SELECT ticket_id FROM '.TICKET_TABLE.' WHERE ticketID='.db_input($id))))
return Ticket::genExtRandID();
return $id;
}
Lines и теория вероятностей