Delphi 10.2 JSON与对象/结构体序列化性能提高100多倍

今天在盒子闲逛,无意中看到有人说XE7自带的Json对象序列化很慢,帖子在这里:http://bbs.2ccc.com/topic.asp?topicid=464378;经过测试的确如此。
     但是 D10.2后,自带的 Json 做了优化,性能大大的提高了100多倍。

和其他json库对比了序列化和反序列化性能,JsonDataObjects 性能最好,但是只支持简单的对象,不支持结构体,QJson 则不支持动态数组,不支持 Attributes (RTTI),比如需要过滤某个字段,自带和 XSuperObject 可支持。总体来说,个人比较喜欢10.2新增的TJsonSerializer,使用方便,无需第三方库。

全部代码如下:

unit Unit1;
{$DEFINE XSuperObject}
{$DEFINE QJson }
{$DEFINE JsonDataObjects}

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls,
  Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Samples.Spin
{$IF CompilerVersion>31.0}, System.JSON.Types, System.JSON.Serializers{$ENDIF};

type

{$IF CompilerVersion>31.0}
  [JsonSerialize(TJsonMemberSerialization.&Public)]
{$ENDIF}

  TObj1 = class
  private
    F_i: Integer;
    f_d: TDateTime;
    f_s: string;
  //  f_a: TArray<string>;
  public
    constructor Create;
  published
    property field_s: string read f_s write f_s;
    property field_i: Integer read F_i write F_i;
    property field_d: TDateTime read f_d write f_d;
  //  property field_a: TArray<string> read f_a write f_a;
  end;

  TForm1 = class(TForm)
    btnObjectToJsonString: TButton;
    btnJsonSerializer: TButton;
    mmoLog: TMemo;
    seTestNumber: TSpinEdit;
    lbl1: TLabel;
    btnXSuperObject: TButton;
    btnQJson: TButton;
    btnJsonDataObjects: TButton;
    btnParseFile: TButton;
    dlgOpen1: TOpenDialog;
    procedure btnObjectToJsonStringClick(Sender: TObject);
    procedure btnJsonSerializerClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnXSuperObjectClick(Sender: TObject);
    procedure btnQJsonClick(Sender: TObject);
    procedure btnJsonDataObjectsClick(Sender: TObject);
    procedure btnParseFileClick(Sender: TObject);
  private
    procedure Log(const S: string);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  TestNumber: Integer;

implementation

uses
  System.Diagnostics,
  System.IOUtils,
  REST.JSON,
  System.JSON,
{$IFDEF JsonDataObjects}
  JsonDataObjects,
{$ENDIF}
{$IFDEF XSuperObject}
  XSuperObject,
{$ENDIF}
{$IFDEF QJson}
  qjson,
{$ENDIF}
  rtcMW.System.JSONHelper;

{$R *.dfm}

function GetFileSize(const AFileName: string): Int64;
var
  AttributeData: TWin32FileAttributeData;
begin
  if not GetFileAttributesEx(PChar(AFileName), GetFileExInfoStandard, @AttributeData) then
    RaiseLastOSError;
  Int64Rec(Result).Lo := AttributeData.nFileSizeLow;
  Int64Rec(Result).Hi := AttributeData.nFileSizeHigh;
end;

procedure TForm1.btnObjectToJsonStringClick(Sender: TObject);
var
  Foo: TObj1;
  I: Integer;
  sw: TStopwatch;
  JSON: string;
begin
  TestNumber := seTestNumber.Value;

  sw := TStopwatch.StartNew;
  for I := 1 to TestNumber - 1 do
  begin
    Foo := TObj1.Create;
    try
      Foo.field_s := ‘Hello World‘;
      Foo.field_i := 42;
      Foo.field_d := Now;
      JSON := REST.JSON.TJson.ObjectToJsonString(Foo);
    finally
      Foo.Free;
    end;
  end;
  Log(‘TJson.ObjectToJsonString:‘ + sw.ElapsedMilliseconds.ToString + ‘ ms ‘ + JSON);

  sw := TStopwatch.StartNew;
  for I := 1 to TestNumber - 1 do
  begin
    Foo := REST.JSON.TJson.JsonToObject<TObj1>(JSON);
    try
    finally
      Foo.Free;
    end;
  end;
  Log(‘TJson.ObjectToJsonString:‘ + sw.ElapsedMilliseconds.ToString + ‘ ms‘);
  Log(‘=======================‘);
end;

procedure TForm1.btnXSuperObjectClick(Sender: TObject);
{$IFDEF XSuperObject}
var
  Foo: TObj1;
  I: Integer;
  sw: TStopwatch;
  AJson: string;
{$ENDIF}
begin
{$IFDEF XSuperObject}
  TestNumber := seTestNumber.Value;
  sw := TStopwatch.StartNew;

  for I := 0 to TestNumber - 1 do
  begin
    Foo := TObj1.Create;
    try
      Foo.field_s := ‘Hello World‘;
      Foo.field_i := 42;
      Foo.field_d := Now;
      AJson := XSuperObject.TJson.SuperObject<TObj1>(Foo).AsJSON();
    finally
      Foo.Free;
    end;

  end;
  Log(‘XSuperObject.TJson.SuperObject:‘ + sw.ElapsedMilliseconds.ToString + ‘ ms  ‘ + AJson);

  for I := 0 to TestNumber - 1 do
  begin
    Foo := XSuperObject.TJson.Parse<TObj1>(AJson);
    try
    finally
      Foo.Free;
    end;

  end;
  Log(‘XSuperObject.TJson.Parse:‘ + sw.ElapsedMilliseconds.ToString + ‘ ms‘);
  Log(‘=======================‘);
{$ENDIF}

end;

procedure TForm1.btnJsonDataObjectsClick(Sender: TObject);
{$IFDEF JsonDataObjects}
var
  Foo: TObj1;
  I: Integer;
  sw: TStopwatch;
  AJson: string;
  JsonObj: JsonDataObjects.TJsonObject;
{$ENDIF}
begin
{$IFDEF JsonDataObjects}
  TestNumber := seTestNumber.Value;
  sw := TStopwatch.StartNew;

  JsonObj := JsonDataObjects.TJsonObject.Create;
  for I := 0 to TestNumber - 1 do
  begin
    Foo := TObj1.Create;
    try
      Foo.field_s := ‘Hello World‘;
      Foo.field_i := 42;
      Foo.field_d := Now;
      JsonObj.FromSimpleObject(Foo);
      AJson := JsonObj.ToJSON();
    finally
      Foo.Free;
    end;

  end;
  Log(‘JsonDataObjects.FromSimpleObject:‘ + sw.ElapsedMilliseconds.ToString + ‘ ms ‘ + AJson);
  JsonObj.Free;

  sw := TStopwatch.StartNew;
  for I := 1 to TestNumber - 1 do
  begin
    JsonObj := JsonDataObjects.TJsonObject.Parse(AJson) as JsonDataObjects.TJsonObject;
    Foo := TObj1.Create;
    try
      JsonObj.ToSimpleObject(Foo);
    finally
      Foo.Free;
      JsonObj.Free;
    end;
  end;
  Log(‘JsonDataObjects.ToSimpleObject:‘ + sw.ElapsedMilliseconds.ToString + ‘ ms‘);
  Log(‘=======================‘);
{$ENDIF}
end;

procedure TForm1.btnParseFileClick(Sender: TObject);

var
  JsonObj: System.JSON.TJsonObject;
  JsonObj1: JsonDataObjects.TJsonObject;
{$IFDEF QJson}
  JsonObj2: TQJson;
{$ENDIF}
  sw: TStopwatch;
  FileName: string;
begin
  if not dlgOpen1.Execute() then
    Exit;
  FileName := dlgOpen1.FileName;
  Log(Format(‘%s,FileSize:%d Byte‘, [FileName, GetFileSize(FileName)]));
  Log(‘=======================‘);

  sw := TStopwatch.StartNew;
  JsonObj := System.JSON.TJsonObject.LoadFromFile(FileName).AsJsonObject;
  try
    if JsonObj = nil then
      raise Exception.CreateFmt(‘%s 不是有效的 JSON 文件‘, [FileName]);
    // Log(JsonObj.GetValue<string>(‘meta[0].field_name‘));
    Log(‘System.Json.TJsonObject.LoadFromFile:‘ + sw.ElapsedMilliseconds.ToString + ‘ ms‘);
  finally
    JsonObj.Free;
  end;
{$IFDEF JsonDataObjects}
  sw := TStopwatch.StartNew;
  JsonObj1 := JsonDataObjects.TJsonObject.Create;
  try
    JsonObj1.LoadFromFile(FileName);
    if JsonObj1 <> nil then
    begin
      Log(‘JsonDataObjects.TJsonObject.LoadFromFile:‘ + sw.ElapsedMilliseconds.ToString + ‘ ms‘);
    end;
  finally
    JsonObj1.Free;
  end;
{$ENDIF}
{$IFDEF QJson}
  sw := TStopwatch.StartNew;
  JsonObj2 := TQJson.Create;
  try
    JsonObj2.LoadFromFile(FileName);
    if JsonObj2 <> nil then
    begin
      // Log(Json.ItemByPath(‘meta[0].field_name‘).AsString);
      Log(‘TQJson.LoadFromFile:‘ + sw.ElapsedMilliseconds.ToString + ‘ ms‘);
    end;
  finally
    JsonObj2.Free;
  end;
{$ENDIF}

end;

procedure TForm1.btnJsonSerializerClick(Sender: TObject);
{$IF CompilerVersion>31.0}
var
  Foo: TObj1;
  I: Integer;
  sw: TStopwatch;
  AJson: string;
  Serializer: TJsonSerializer;
{$ENDIF}
begin
{$IF CompilerVersion>31.0}
  TestNumber := seTestNumber.Value;
  sw := TStopwatch.StartNew;
  Serializer := TJsonSerializer.Create;
  try
    Serializer.DateTimeZoneHandling := TJsonDateTimeZoneHandling.Utc;
    for I := 0 to TestNumber - 1 do
    begin
      Foo := TObj1.Create;
      try
        Foo.field_s := ‘Hello World‘;
        Foo.field_i := 42;
        Foo.field_d := Now;
        AJson := Serializer.Serialize<TObj1>(Foo);
      finally
        Foo.Free;
      end;

    end;
    Log(‘TJsonSerializer.Serialize:‘ + sw.ElapsedMilliseconds.ToString + ‘ ms ‘ + AJson);

    sw := TStopwatch.StartNew;
    for I := 1 to TestNumber - 1 do
    begin
      Foo := Serializer.Deserialize<TObj1>(AJson);
      try
      finally
        Foo.Free;
      end;
    end;
    Log(‘TJsonSerializer.Deserialize:‘ + sw.ElapsedMilliseconds.ToString + ‘ ms‘);

  finally
    FreeAndNil(Serializer);
  end;
  Log(‘=======================‘);
{$ENDIF}
end;

procedure TForm1.btnQJsonClick(Sender: TObject);
{$IFDEF QJson}
var
  Foo: TObj1;
  I: Integer;
  sw: TStopwatch;
  AJson: string;
  Serializer: TQJson;
{$ENDIF}
begin
{$IFDEF QJson}
  TestNumber := seTestNumber.Value;
  sw := TStopwatch.StartNew;
  Serializer := TQJson.Create;
  for I := 0 to TestNumber - 1 do
  begin
    Foo := TObj1.Create;
    try
      Foo.field_s := ‘Hello World‘;
      Foo.field_i := 42;
      Foo.field_d := Now;
      Serializer.FromRtti(Foo);
      AJson := Serializer.AsJSON;
    finally
      Foo.Free;
    end;

  end;
  Log(‘TQJson.FromRtti:‘ + sw.ElapsedMilliseconds.ToString + ‘ ms  ‘ + AJson);

  for I := 0 to TestNumber - 1 do
  begin
    Serializer.Parse(AJson);
    Foo := TObj1.Create;
    try
      Serializer.ToRtti(Foo);
    finally
      Foo.Free;
    end;

  end;
  Serializer.Free;
  Log(‘TQJson.ToRtti:‘ + sw.ElapsedMilliseconds.ToString + ‘ ms‘);
  Log(‘=======================‘);
{$ENDIF}
end;

procedure TForm1.FormCreate(Sender: TObject);
const
  // D2010~D10.2
  DelphiIDEVers: array [21 .. 32] of string = (
    ‘Delphi 2010‘,
    ‘Delphi XE‘,
    ‘Delphi XE2‘,
    ‘Delphi XE3‘,
    ‘Delphi XE4‘,
    ‘Delphi XE5‘,
    ‘Delphi XE6‘,
    ‘Delphi XE7‘,
    ‘Delphi XE8‘,
    ‘Delphi 10 Seattle‘,
    ‘Delphi 10.1 Berlin‘,
    ‘Delphi 10.2 Tokyo‘);
begin
{$IFDEF WIN64}
  Caption := Caption + ‘ (64-bit)‘;
{$ENDIF}
  Caption := Caption + ‘ - ‘ + DelphiIDEVers[Trunc(CompilerVersion)];

{$IF CompilerVersion<32.0}
  btnJsonSerializer.Enabled := False;
{$ENDIF}

{$IFNDEF XSuperObject}
  btnXSuperObject.Enabled := False;
{$ENDIF}
{$IFNDEF JsonDataObjects}
  btnJsonDataObjects.Enabled := False;
{$ENDIF}
{$IFNDEF QJson}
  btnQJson.Enabled := False;
{$ENDIF}
  ReportMemoryLeaksOnShutdown := True;
end;

procedure TForm1.Log(const S: string);
begin
  mmoLog.Lines.Add(S);
end;

{ TObj1 }

constructor TObj1.Create;
begin
  inherited;
 { SetLength(f_a, 4);
  f_a[0] := ‘全能中间件‘;
  f_a[1] := ‘QQ:64445322‘;
  f_a[2] := ‘淘宝:https://imaps.taobao.com/‘;
  f_a[3] := ‘没有Unicode?\\//‘;  }
end;

end.
时间: 2024-09-29 22:33:06

Delphi 10.2 JSON与对象/结构体序列化性能提高100多倍的相关文章

go语音之进阶篇json解析到结构体

1.json解析到结构体 示例: package main import ( "encoding/json" "fmt" ) type IT struct { Company string `json:"company"` Subjects []string `json:"subjects"` //二次编码 IsOk bool `json:"isok"` Price float64 `json:"

Swift学习笔记(10):类和结构体

目录: 基本 基本 使用class和struct关键字定义类和结构体. ?类是引用类型,结构体是值类型 ?值类型被赋予给一个变量.常量或被传递给一个函数时,已值拷贝方式传递 声明:该系列内容均来自网络或电子书籍,只做学习总结!

json数据转换成结构体

package main import ( "encoding/json" "fmt" ) type IT1 struct { Company string `json:"company"` Subjects []string `json:"subjects"` IsOk bool `json:"isok"` Price float64 `json:"price"` } type IT2

第4章&#160;类与对象 结构体与联合体

原文地址:https://www.cnblogs.com/ZHONGZHENHUA/p/10241560.html

60_通过结构体生成json

1.json是跨平台.跨语言的数据交换语言 JSON (JavaScript Object Notation)是一种比XML更轻量级的数据交换格式,在易于人们阅读和编写的同时,也易于程序解析和生成.尽管JSON是JavaScript的一个子集,但JSON采用完全独立于编程语言的文本格式,且表现为键/值对集合的文本描述形式(类似一些编程语言中的字典结构),这使它成为较为理想的.跨平台.跨语言的数据交换语言. package main import ( "encoding/json" &q

Go的结构体

Go的结构体 结构体 Go语言提供了一种自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称struct 结构体的定义 type 类型名 struct { 字段名 字段类型 字段名 字段类型 - } 类型名:自定义结构体的名称,在同一个包内不能重复 字段名:结构体中的字段名必须惟一 字段类型:表示结构体字段的具体类型 例子一 type persion struct { name string city string age int8 } 结构体实例化 只有当结构体实例化时,才

关于OC中直接打印结构体,点(CGRect,CGSize,CGPoint,UIOffset)等数据类型

关于OC直接打印结构体,点(CGRect,CGSize,CGPoint,UIOffset)等数据类型,我们完全可以把其转换为OC对象来进项打印调试,而不必对结构体中的成员变量进行打印.就好比我们可以使用NSStringFromCGRect(CGRect rect)来直接打印一个结构体,其他打印可以参考以下内容 UIKIT_EXTERN NSString *NSStringFromCGPoint(CGPoint point); UIKIT_EXTERN NSString *NSStringFrom

C语言结构体的字节对齐原则

转载:http://blog.csdn.net/shenbin1430/article/details/4292463 为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址

c/c++ 结构体传参问题

c/c++的结构体传参可以有三种方式: 1.传递结构体变量,值传递 2.传递结构体指针,地址传递 3.传递结构体成员,可是值传递也可以是地址传递 根据代码示例: 1.传递结构体变量 1 #include<iostream> 2 #define COMMANDLENGTH 100 3 using std::cout; 4 using std::endl; 5 //注意 c和c++中struct和typedef struct有区别. 6 struct Message{ 7 int oneField