Справочная система Delphi 2010 описывает тип TValue, используемый модулем RTTI для хранения значений произвольных типов, как "облегченная версия типа Variant". Увидев это, я задался вопросом, насколько он легковеснее? Как быстро работает TValue?
К счастью, среди известных мне новых возможностей Delphi 2010 – модуль диагностики (Diagnostics), который предоставляет нам объект TStopwatch – простой таймер позволяющий засечь время выполнения операций и тем самым облегчить написание простого теста скорости.
Я ожидал, что скорость работы TValue будет сравнима со скоростью Variant, или возможно немного больше. Для проверки, я написал следующую программку:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils, rtti, diagnostics;
const
HUNDRED_MILLION = 100000000;
procedure tryTValue;
var
i: integer;
j: TValue;
value: integer;
begin
for I := 1 to HUNDRED_MILLION do
begin
j := i;
value := j.AsInteger;
end;
end;
procedure tryVariants;
var
i: integer;
j: variant;
value: integer;
begin
for I := 1 to HUNDRED_MILLION do
begin
j := i;
value := j;
end;
end;
var
stopwatch: TStopWatch;
begin
try
stopwatch := TStopWatch.StartNew;
tryVariants;
stopwatch.Stop;
writeln('Variants: ', stopwatch.ElapsedMilliseconds);
stopwatch := TStopWatch.StartNew;
tryTValue;
stopwatch.Stop;
writeln('TValues: ', stopwatch.ElapsedMilliseconds);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.
Конечно, этот тест - не исчерпывающая проверка возможностей TValue, но результаты поучительны. Когда я запустил его на своем рабочем компьютере (высокопроизводительный ноутбук Alienware), тест Variant выполнился почти мгновенно, а тест TValue выполнялся так долго, что я решил, что он завис и остановил его.
Затем я запустил тест снова и получил следующие результаты (в миллисекундах):
Variants: 717По крайней мере, для этой конкретной операции, TValue в 43.52167832167832 раза медленнее, чем Variant!
TValues: 31131
От меня.
Вообще то 31131 поделить на 717 будет равно 43.41841004 ;)
Что бы проверить результат, я запустил несколько тестов на своей домашней "dev machine".
Тест #1. Запустил исходный тест и получил такую же разницу скорости - в 43.17657992 раза:
Variants: 538Тест #2. Переставил местами вызов tryTValue и tryVariants и снова получил 43.376404494:
TValues: 23229.
TValues: 23163Тест #3. Закомментировав обратное присвоение TValue и Variant целой переменной ("value := j.AsInteger" и "value := j") я получил для TValue более "веселый" результат:
Variants: 534.
Variants: 535Присвоение целого значения TValue медленнее присвоения целого значения Variant всего в 9.65981308 раза. А значит основное падение скорости вызвано AsInteger.
TValues: 5168
Тест #4. В процедуре tryTValue я заменил "value := j.AsInteger" на "value := j.AsOrdinal"
Variants: 536В результате общее падение скорости всего в 10.93656716 раза!
TValues: 5862
Тест #5. AsOrdinal возвращает значение типа Int64, поэтому в процедуре tryTValue я заменил "value := j.AsInteger" на "value := j.AsInt64" и получил падение скорости в 54,25981308 раза!!!
Variants: 535Вывод: "value := j.AsOrdinal" у TValue работает почти так же быстро, как и "value := j" для Variant. А методы AsInteger и AsInt64 – лучше не использовать. Но все равно, главный вывод: TValue – "тормоз"!
TValues: 29029
Напоследок, я проверил с помощью функции SizeOf число байт, которые занимали переменные: переменная типа Variant занимала – 24 байта, а TValue – всего 16. Может в этом проявляется "облегченность" типа TValue? Тогда, храните числа в integer – они будут занимать 4 байта ;)
Также, очень интересное исследование провёл автр библиотеки OmniThreadLibrary(
ОтветитьУдалитьhttp://17slon.com/blogs/gabr/2010/03/..d-comparison-variant-tvalue-and.html).
Всё не так плохо, просто нужно помнить несколько простых правил при работе с такими типами и использовать их к месту.
Автору неплохо было бы вспомнить, как определяется точность результата деления и что такое значащие разряды
ОтветитьУдалитьЭто вы на что намекаете?
ОтветитьУдалить>Напоследок, я проверил с помощью функции SizeOf число байт, которые занимали переменные: переменная типа Variant занимала – 24 байта, а TValue – всего 16.
ОтветитьУдалитьХм, у меня с точностью наоборот