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

和其他json库对比了序列化和反序列化性能,JsonDataObjects 性能最好,但是只支持简单的对象,不支持结构体,QJson 则不支持动态数组,不支持 Attributes (RTTI),比如需要排除某些字段,System.JSON 和 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 := to TestNumber - do
begin
Foo := TObj1.Create;
try
Foo.field_s := 'Hello World';
Foo.field_i := ;
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 := to TestNumber - 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 := to TestNumber - do
begin
Foo := TObj1.Create;
try
Foo.field_s := 'Hello World';
Foo.field_i := ;
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 := to TestNumber - 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 := to TestNumber - do
begin
Foo := TObj1.Create;
try
Foo.field_s := 'Hello World';
Foo.field_i := ;
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 := to TestNumber - 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 := to TestNumber - do
begin
Foo := TObj1.Create;
try
Foo.field_s := 'Hello World';
Foo.field_i := ;
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 := to TestNumber - 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 := to TestNumber - do
begin
Foo := TObj1.Create;
try
Foo.field_s := 'Hello World';
Foo.field_i := ;
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 := to TestNumber - 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 [ .. ] 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.
Delphi 10.2 JSON与对象/结构体序列化性能提高100多倍的更多相关文章
- JSON还原为结构体
JSON还原为结构体 1)JSON字符串还原为结构体: 2)访问结构体的字段值: 本例运行效果图: uses SynCommons; const // JSON字符串 JSON1 = '{' + #1 ...
- go语言之进阶篇json解析到结构体
1.json解析到结构体 示例: package main import ( "encoding/json" "fmt" ) type IT struct { ...
- [GO]json解析到结构体
package main import ( "encoding/json" "fmt" ) type IT struct { Company string `j ...
- Swift学习笔记(10):类和结构体
目录: 基本 属性 方法 下标 继承 基本 使用class和struct关键字定义类和结构体. ・类是引用类型,结构体和枚举是值类型 ・值类型被赋予给一个变量.常量或被传递给一个函数时,已值拷贝方式传 ...
- go get请求 json字符串转为结构体
package main import ( "io/ioutil" "fmt" "net/http" "encoding/json ...
- json数据转换成结构体
package main import ( "encoding/json" "fmt" ) type IT1 struct { Company string ` ...
- 在线JSON转Go 结构体,在线JSON转Go Struct
在线转换https://oktools.net/json2go
- 结构体序列为JSON
结构体序列为JSON 本例运行效果图: uses SynCommons; const /// JSON字符串 JSON1 = '{' + #13#10 + '"glossary": ...
- 深入delphi编程理解之消息(二)发送消息函数及消息编号、消息结构体的理解
一.delphi发送消息的函数主要有以下三个: (一).SendMessage函数,其原型如下: function SendMessage( hWnd: HWND; {目标句柄} Msg: UINT; ...
随机推荐
- comlink 是来自google chrome 团队的简化webwokers 开发的类库
comlink 可以帮助我们简单webworkers 的开发,同时很小(1.1kb),具体使用我们可以看下面 一张图 说明 comlink 使用起来也比较方便,官方也提供了完整的api 文档 参考资 ...
- 9-ESP8266 SDK开发基础入门篇--编写串口上位机软件
https://www.cnblogs.com/yangfengwu/p/11087613.html 页面修改成这样子 现在看串口发送数据 点击点亮 发送0xaa 0x55 0 ...
- 将 iTunes 降级到支持安装 .ipa 文件的版本
将 iTunes 降级到支持安装 .ipa 文件的版本 新版的 iTunes 再也不支持安装 .ipa 文件了,但是 Apple 官网依旧保留了旧版 iTunes 的下载渠道.(点击进入) 安装完上面 ...
- 【cf contest 1119 G】Get Ready for the Battle
题目 你有\(n\)个士兵,需要将他们分成\(m\)组,每组可以为0: 现在这些士兵要去攻打\(m\)个敌人,每个敌人的生命值为\(hp_i\) : 一轮游戏中一组士兵选定一个攻打的敌人,敌人生命值- ...
- Java-根据经纬度计算距离(百度地图距离)
最近碰到一个需求,需要根据两个点的经纬度查询两点的距离.感觉以后还会用到,所以小记一波. 第一步:添加Maven依赖. <dependency> <groupId>org.ga ...
- springboot带有进度条的上传
一.说明 最近要做文件上传,在网上找了很久都没有一个全面的示例,特此记录下来分享给大家. 1.文件上传接口可按照springboot默认实现,也可用commons-fileupload组件,本示例使用 ...
- 【大数据作业九】安装关系型数据库MySQL 安装大数据处理框架Hadoop
作业要求:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3161 4.简述Hadoop平台的起源.发展历史与应用现状. 列举发展过程中 ...
- css3学习之--伪类与圆角
随着css3.0的发布到逐渐完善,目前已经大部分浏览器已经能较好地适配,所以写一些css3的学习经历,分享心得,主要以案例讲解为主,话不多说,今天以css3的新增的“圆角”属性来讲解,基于web画一个 ...
- 推荐一款不错的MarkDown在线编辑器
StackEdit链接:https://stackedit.io/editor StackEdit可以实现同步编辑预览,如下图展示: 菜单界面 功能包括: 管理多个 MarkDown 文档.可在线或离 ...
- Jmeter5.11安装
jmeter5.11要对应jdk1.8以上版本 1.选择zip后缀进行下载 2.配置环境变量 (1)电脑桌面---->"计算机"图标---->鼠标右键选择"属 ...