Delphi; производительность передачи строк const по сравнению с передачей строк var - PullRequest
10 голосов
/ 23 декабря 2009

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

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

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

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

Ответы [ 5 ]

12 голосов
/ 23 декабря 2009

Нет, не должно быть никакой разницы в производительности между использованием 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, это должно оказать гораздо большее влияние на производительность.

9 голосов
/ 24 декабря 2009

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 всегда является наиболее эффективным способом передачи параметра любого типа, но вы не должны делать никаких предположений о том, есть ли у вас копия значения, которое было передано вызывающей стороной, или ссылка в какое-либо (потенциально мутировавшее с помощью другого кода, который вы можете вызвать) местоположение.

4 голосов
/ 07 мая 2011

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

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

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

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

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

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

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

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

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

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

3 голосов
/ 23 декабря 2009

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

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

2 голосов
/ 24 декабря 2009

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

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

My 2 ¢ ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...