Насколько эффективный станд.:: строка по сравнению с завершенными пустым указателем строками?

Для свойства установлено значение по умолчанию, в данном случае null. Возможно, вы захотите установить его в конструкторе и сделать его закрытым, чтобы позже его нельзя было установить на null.

public class Orders
{
    public Orders()
    {
        ItemList = new List<Items>();
    }

    public List<Items> ItemList { get; private set; }
}
13
задан Abhinav Gauniyal 21 February 2016 в 09:46
поделиться

11 ответов

Хорошо существуют определенно известные проблемы относительно производительности строк и других контейнеров. Большинство из них имеет отношение к временным файлам и ненужным копиям.

не слишком трудно использовать его право, но также довольно легко Сделать Это Неправильно. Например, если Вы видите, что Ваш код принимает строки значением, где Вам не нужен модифицируемый параметр, Вы Делаете Это Неправильно:

// you do it wrong
void setMember(string a) {
    this->a = a; // better: swap(this->a, a);
}

Вы лучше взяли это ссылкой константы или сделали операцию подкачки внутри вместо еще одной копии. Потеря производительности увеличивается для вектора или списка в этом случае. Однако Вы правы определенно, что существуют известные проблемы. Например, в этом:

// let's add a Foo into the vector
v.push_back(Foo(a, b));

Мы создаем один временный файл Foo только для добавления нового Foo в наш вектор. В ручном решении, которое могло бы создать Foo непосредственно в вектор. И если вектор достигает своего полного предела, он должен перераспределить больший буфер памяти для своих элементов. Что это делает? Это копирует каждый элемент отдельно в их новое место с помощью их конструктора копии. Ручное решение могло бы вести себя более интеллектуальное, если оно знает тип элементов заранее.

Другой типичной проблемой являются представленные временные файлы. Взгляните на это

string a = b + c + e;

существуют загрузки созданных временных файлов, который Вы могли бы избежать в настраиваемом решении, чтобы Вы на самом деле оптимизировали на производительность. Тогда, интерфейс std::string был разработан, чтобы быть дружественной копией на записи. Однако с потоками, становящимися более популярной, прозрачной копией на записи, строки имеют проблемы при сохранении их состояния последовательным. Недавние реализации имеют тенденцию избегать копии на строках записи и вместо этого применять другие приемы в соответствующих случаях.

большинство тех проблем решено однако для следующей версии Стандарта. Например, вместо push_back, можно использовать emplace_back для прямого создания Foo в вектор

v.emplace_back(a, b);

И вместо того, чтобы создать копии в конкатенации выше, std::string распознает, когда он связывает временные файлы, и оптимизируйте для тех случаев. Перераспределение также постарается не делать копии, но переместит элементы в соответствующих случаях в их новые места.

Для превосходного чтения, рассмотрите Конструкторы Перемещения Andrei Alexandrescu.

Иногда, однако, сравнения также имеют тенденцию быть несправедливыми. Стандартные контейнеры должны поддерживать функции, которые они должны поддерживать. Например, если Ваш контейнер не сохраняет ссылки на элемент карты допустимыми при добавлении/удалении элементов из карты, то сравнение "более быстрой" карты к стандартной карте может стать несправедливым, потому что стандартная карта должна гарантировать, чтобы элементы продолжали быть допустимыми. Это было просто примером, конечно, и существует много таких случаев, которые необходимо иметь в виду при заявлении, что "мой контейнер быстрее, чем стандартные!!!".

39
ответ дан 1 December 2019 в 17:17
поделиться

Значительная часть причины могла бы быть тем, что подсчет ссылок больше не используется в современных реализациях STL.

Вот история (кто-то исправляет меня, если я неправ): в начале реализации STL использовали подсчет ссылок, и были быстры, но не ориентированы на многопотоковое исполнение - конструкторы ожидали, что прикладные программисты вставят свои собственные механизмы блокировки в более высоких уровнях, сделают их ориентированными на многопотоковое исполнение, потому что, если бы блокировка была сделана на 2 уровнях тогда, это замедлило бы вещи вниз вдвое больше.

Однако программисты мира были слишком не осведомлены или ленивы для вставки блокировок везде. Например, если рабочий поток в многопоточной программе должен был считать станд.:: представьте параметр командной строки в виде строки, тогда блокировка была бы необходима даже только для чтения строки, иначе катастрофические отказы могли последовать. (2 потока увеличивают подсчет ссылок одновременно на другом ЦП (+1), но постепенно уменьшают его отдельно (-2), таким образом, подсчет ссылок понижается для обнуления, и память освобождена.)

, Таким образом, конструкторы угробили подсчет ссылок и вместо этого имели каждый станд.:: представьте в виде строки всегда владеют его собственной копией строки. Больше программ работало, но они были все медленнее.

Поэтому теперь, даже скромное присвоение одного станд.:: представьте в виде строки другому, (или эквивалентно, передавая станд.:: представьте в виде строки в качестве параметра к функции), берет приблизительно 400 команд машинного кода вместо 2, которые требуется для присвоения символа*, замедление 200 раз.

я протестировал величину неэффективности станд.:: строка на одной главной программе, которая имела полное замедление приблизительно 100% по сравнению с завершенными пустым указателем строками. Я также протестировал необработанный станд.:: строковое присвоение с помощью следующего кода, который сказал что станд.:: строковое присвоение было в 100-900 раз медленнее. (Я испытал затруднения при измерении скорости символа* присвоение). Я также отладил в станд.:: строковый оператор = () функция - я закончил по колено в стеке, приблизительно 7 слоев глубоко, прежде, чем совершить нападки 'memcpy ()'.

я не уверен, что существует любое решение. Возможно, при необходимости в программе, чтобы быть быстрыми, используйте простой C++, и если Вы более обеспокоены своей собственной производительностью, необходимо использовать Java.

#define LIMIT 800000000
clock_t start;
std::string foo1 = "Hello there buddy";
std::string foo2 = "Hello there buddy, yeah you too";
std::string f;

start = clock();
for (int i=0; i < LIMIT; i++) {
    stop();
    f    = foo1;
    foo1 = foo2;
    foo2 = f;
}
double stl = double(clock() - start) / CLOCKS_PER_SEC;

start = clock();
for (int i=0; i < LIMIT; i++) {
    stop();
}
double emptyLoop = double(clock() - start) / CLOCKS_PER_SEC;

char* goo1 = "Hello there buddy";
char* goo2 = "Hello there buddy, yeah you too";
char *g;

start = clock();
for (int i=0; i < LIMIT; i++) {
    stop();
    g = goo1;
    goo1 = goo2;
    goo2 = g;
}
double charLoop = double(clock() - start) / CLOCKS_PER_SEC;

TfcMessage("done", 'i', "Empty loop = %1.3f s\n"
                        "char* loop = %1.3f s\n"
                        "std::string loop = %1.3f s\n\n"
                        "slowdown = %f", 
                        emptyLoop, charLoop, stl, 
                        (stl - emptyLoop) / (charLoop - emptyLoop));
-5
ответ дан 1 December 2019 в 17:17
поделиться

Я сказал бы, что реализации STL лучше, чем традиционные реализации. Также сделал Вы пытаетесь использовать список вместо вектора, потому что вектор эффективен для некоторой цели, и список эффективен для некоторого другого

0
ответ дан 1 December 2019 в 17:17
поделиться

Если используется правильно, станд.:: строка так же эффективна как символ*, но с дополнительной защитой.

при испытании проблем производительности с STL вероятно, что Вы делаете что-то не так.

Кроме того, реализации STL не являются стандартными через компиляторы. Я знаю, что STL и STLPort SGI работают обычно хорошо.

Тем не менее и я абсолютно серьезен, Вы могли быть гением C++ и создали код, который намного более сложен, чем STL. Маловероятно, но кто знает, Вы могли быть LeBron James C++.

0
ответ дан 1 December 2019 в 17:17
поделиться

Хорошая производительность не всегда легка с STL, но обычно, это разработано, чтобы дать Вам питание. Я нашел "Эффективный STL Scott Meyers" разоблачение для понимания, как иметь дело с STL эффективно. Читайте!

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

Обычно любой класс, разработанный к Вашим определенным потребностям, разобьет универсальный класс, это разработано для общего случая. Но учитесь использовать универсальный класс хорошо и учиться ехать 80:20 правила, и Вы будете намного более эффективными, чем кто-то прокручивающий все самостоятельно.

<час>

Один определенный недостаток std::string состоит в том, что он не дает гарантии исполнения, который имеет смысл. Как Tim Cooper упомянул, STL не говорит, создает ли строковое присвоение глубокую копию. Это хорошо для универсального класса, потому что подсчет ссылок может стать реальным уничтожителем в очень параллельных приложениях, даже при том, что это обычно - лучший способ для единственного потокового приложения.

2
ответ дан 1 December 2019 в 17:17
поделиться

Они не пошли не так, как надо. Реализация STL вообще говоря, лучше, чем Ваш.

я уверен, что можно записать что-то лучше для очень особого случая, но фактор 2 слишком много..., действительно необходимо делать что-то не так.

0
ответ дан 1 December 2019 в 17:17
поделиться

Если у Вас есть признак возможного размера Вашего вектора, можно предотвратить чрезмерный, изменяет размеры путем вызова резерва () перед заполнением его.

2
ответ дан 1 December 2019 в 17:17
поделиться

Вы несомненно делаете что-то не так или по крайней мере не выдерживаете сравнение "справедливо" между STL и Вашим собственным кодом. Конечно, трудно быть более конкретным без кода для взгляда на.

могло случиться так структурированием кода с помощью STL способом, который заставляет больше конструкторов работать, или не многократное использование выделенных объектов способом, который соответствует тому, что Вы делаете при реализации операций сами и так далее.

5
ответ дан 1 December 2019 в 17:17
поделиться

Когда запись кода C++ с помощью любого служебного класса (или STL или собственное) вместо, например, старый добрый пустой указатель C завершила строки, Вам нужны к rememeber несколько вещей.

  • , Если Вы сравниваете без оптимизаций компилятора на (особенно встраивание функции), классы проиграют. Они не создаются-ins, даже stl. Они реализованы с точки зрения вызовов метода.

  • не создают ненужные объекты.

  • не копируют объекты, если это возможно.

  • Передача возражает как ссылки, не копии, если это возможно,

  • Использование более специализированный метод и функции и высокоуровневые алгоритмы. Например:

    std::string a = "String a"
    std::string b = "String b"
    
    // Use
    a.swap(b);
    
    // Instead of
    std::string tmp = a;
    a = b;
    b = tmp;
    

И заключительное примечание. Когда Ваш подобный C код C++ начинает становиться более сложным, необходимо реализовать более усовершенствованные структуры данных как автоматическое расширение массивов, словарей, эффективных приоритетных очередей. И внезапно Вы понимаете, что это - большая работа, и Ваши классы не действительно быстрее тогда stl. Просто больше багги.

7
ответ дан 1 December 2019 в 17:17
поделиться

Похоже на неправильное использование символа* в коде, который Вы вставили. Если Вы имеете

std::string a = "this is a";
std::string b = "this is b"
a = b;

, Вы выполняете строковую операцию копии. Если Вы делаете то же с символом*, Вы выполняете операцию копии указателя.

станд.:: строковая операция присвоения выделяет достаточно памяти для содержания содержания b в a, затем копирует каждый символ один за другим. В случае символа*, это не делает никакого выделения памяти или копирует отдельные символы один за другим, это просто говорит "теперь точки к той же памяти, что b указывает".

Мое предположение - то, что это то, почему станд.:: строка медленнее, потому что она на самом деле копирует строку, которая, кажется, то, что Вы хотите. Чтобы сделать операцию копии на символе*, необходимо было бы использовать strcpy () функция для копирования в буфер, это уже соответственно измерено. Тогда у Вас будет точное сравнение. Но в целях Вашей программы необходимо почти определенно использовать станд.:: строка вместо этого.

11
ответ дан 1 December 2019 в 17:17
поделиться

Основные правила оптимизации:

  • Правило 1: не делайте этого.
  • Правило 2: (Только для экспертов) еще, не делают этого.

Вы уверенный, что Вы имеете доказанный , что это - действительно STL, который является медленным, а не Ваш алгоритм ?

2
ответ дан 1 December 2019 в 17:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: