Delphi; производительность передаваемых константных строк по сравнению с переданными строками var

Быстрый; Правильно ли я полагаю, что передача строки методу "как CONST" требует большего количества накладных расходов, чем передача строки как "VAR"? Компилятор получит Delphi, чтобы сделать копию строки, а затем передать копию, если строковый параметр объявлен как CONST, правильно?

Причина вопроса немного утомительна; у нас есть утилита Delphi 5, чьи дни действительно пронумерованы (замена находится в разработке). Он выполняет большую обработку строк, часто передавая строки 1-2Kb между различными функциями и процедурами. На протяжении всего кода соблюдалось "правильное" наблюдение за использованием CONST или VAR для передачи параметров (в зависимости от выполняемой работы). Мы просто ищем несколько "быстрых побед", которые могут сбрить несколько микросекунд от времени выполнения, чтобы выдержать нас до тех пор, пока новая версия не будет готова. Мы подумали об изменении диспетчера памяти по умолчанию от Delphi 5 до FastMM, и мы также задались вопросом, стоит ли изменять способ передачи строк - потому что код работает нормально с строками, переданными как const, мы не см. проблему, если мы изменили эти объявления на var - код внутри этого метода не изменит строку.

Но действительно ли это имеет значение в реальных условиях? (Программа действительно просто выполняет большую обработку на этих строках 1kb + ish, несколько сотен строк в минуту в разное время). При повторной записи эти строки хранятся в переменных объектов/классов, поэтому их вообще не копируют и не пропускают одинаково, но в устаревшем коде это очень "старая школа".

Естественно, мы проанализируем общий прогон программы, чтобы увидеть, какую разницу мы сделали, но нет смысла на самом деле пытаться это, если мы категорически ошибаемся в отношении того, как работает строка в первом экземпляре!

Ответ 1

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

procedure TForm1.Button1Click(Sender: TObject);
var
  s: string;
begin
  s := 'foo bar baz';
  UniqueString(s);
  SetConstCaption(s);
  Caption := s;
end;

procedure TForm1.SetConstCaption(const AValue: string);
var
  P: PChar;
begin
  P := PChar(AValue);
  P[3] := '?';
  Caption := AValue;
end;

Это фактически изменит локальную строковую переменную в вызывающем методе, доказав, что передан только указатель на нее.

Но определенно используйте FastMM4, он должен значительно повысить производительность.

Ответ 2

const для параметров в Delphi по существу означает: "Я не буду мутировать это, , и мне также все равно, будет ли это передано по значению или по ссылке - в зависимости от того, что наиболее эффективно в порядке". Полужирная часть важна, потому что она действительно наблюдаема. Рассмотрим этот код:

type TFoo =
  record
    x: integer;
    //dummy: array[1..10] of integer;
  end;

procedure Foo(var x1: TFoo; const x2: TFoo);
begin
  WriteLn(x1.x);
  WriteLn(x2.x);

  Inc(x1.x);
  WriteLn;

  WriteLn(x1.x);
  WriteLn(x2.x);
end;

var
  x: TFoo;
begin
  Foo(x, x);
  ReadLn;
end.

Трюк здесь состоит в том, что мы передаем ту же переменную как var и как const, чтобы наша функция могла мутировать через один аргумент и видеть, влияет ли это на другое. Если вы попробуете его с приведенным выше кодом, вы увидите, что приращение x1.x внутри Foo не меняет x2.x, поэтому x2 передается по значению. Но попробуйте раскомментировать объявление массива в TFoo, чтобы его размер стал больше и снова запустил его - и вы увидите, как x2.x теперь псевдонимы x1.x, поэтому у нас есть сквозная ссылка для x2 сейчас

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

Ответ 3

Это действительно комментарий, но длинный, так что несите меня.

О "так называемой" строке, передаваемой по значению

Delphi всегда передает string и ansistring (исключая WideStrings и ShortStrings) по ссылке, как указатель.
Поэтому строки никогда не передаются по значению. Это можно легко протестировать, передав строки 100 МБ.

Пока вы не меняете их внутри тела вызываемой строки, передача строки принимает время O (1) (и с небольшой константой при этом)

Однако при передаче строки без предложения var или const Delphi делает три вещи.

  • Увеличьте количество ссылок на строку.
  • помещает неявный блок try-finally вокруг процедуры, поэтому уменьшается количество ссылок на параметр строки.
  • Когда строка изменяется (и только тогда), Delphi создает копию строки, уменьшает количество ссылок на переданную строку и использует копию в остальной части подпрограммы. Это подделывает pass by value при этом.

О передаче по ссылке (указатель)

Когда строка передается как const или var, Delphi также передает ссылку (указатель):

  • Количество ссылок строки не увеличивается. (крошечное, крошечное увеличение скорости)
  • Никакая неявная попытка/окончательно помещается в подпрограмму, потому что она не нужна. Это часть 1, почему const/var строковые параметры выполняются быстрее.
  • Когда строка изменена внутри подпрограммы, никакая копия не делает, фактическая строка изменяется. Для параметров const компилятор запрещает чередование строк. Это часть 2, почему var/const строковые параметры работают быстрее.
  • Если вам нужно создать локальный var, чтобы назначить строку; Delphi копирует строку:-) и помещает неявный блок try/finally, устраняя 99% + увеличения скорости строкового параметра const.

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

Ответ 4

Компилятор не будет копировать строку при использовании const afaik. Использование const экономит накладные расходы на увеличение/уменьшение показателя refcounter для используемой строки.

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

Ответ 5

Const - это уже самый эффективный способ передачи параметров функции. Он избегает создания копии (по умолчанию, по значению) или даже передачи указателя (var, по ссылке).
Это особенно верно для струн, и это действительно был путь, когда вычислительная мощность была ограничена и не была потрачена впустую (отсюда и "старая школа" ).

IMO, Const должен был быть стандартным соглашением, вплоть до программиста, чтобы изменить его, когда ему действительно нужно значение или var. Это было бы в большей степени соответствовать общей безопасности Паскаля (как в ограничении возможности стрелять в ногу).

Мои 2 ¢...