[英]Performance storage We are selecting Storage size 250/500GB but no data in IOPS through REST API
[英]Slow performance of TGrid everytime it is created at runtime through dynamic (increasing data) TFDMemTable definition provided REST API data
我正在為 iOS 和 Android 開發 Firemonkey 應用程序。 我注意到,每次使用 TFDMemTable REST API 數據和結構在運行時創建 TGrid 時,應用程序在 iOS 和 Android 調試中的性能都會變慢。
我已經應用了FreeAndNil(TGrid1);
在它一遍又一遍地創建之前清理 TGrid。
一個值得注意的事件是,每次創建 TGrid 時,行都會增加,固定 7 列,性能變慢。 通常,當我達到 10 行或記錄時會發生這種情況。
我的一個大而真正的快速問題:
您認為導致性能下降的開銷來自哪里?
TGrid — 我已經應用了FreeAndNil(TGrid1);
在它的創建之前。
TFMemTable — 我沒有檢查過這個,我不知道如何
TButton — 觸發創建數據並將數據加載到 TGrid 的按鈕。 大部分代碼都在這里
讓我們假設在這種情況之前所有其他組件都工作正常。 如果您願意,我可以與您分享一些代碼,但請指導我您想看哪一個。
更新 1:最小可重復示例
FMX文件
object Form9: TForm9
Left = 0
Top = 0
Caption = 'MRE TeeGrid Runtime'#13#10
ClientHeight = 480
ClientWidth = 294
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
DesignerMasterStyle = 0
object btn1: TButton
Align = Bottom
Position.Y = 440.000000000000000000
Size.Width = 294.000000000000000000
Size.Height = 40.000000000000000000
Size.PlatformDefault = False
TabOrder = 9
Text = 'CREATE TEEGRID'
OnClick = btn1Click
end
object aniSearchProcess: TAniIndicator
Position.X = 128.000000000000000000
Position.Y = 216.000000000000000000
end
object lyt1: TLayout
Align = Client
Size.Width = 294.000000000000000000
Size.Height = 440.000000000000000000
Size.PlatformDefault = False
TabOrder = 11
end
object cur1: TFDGUIxWaitCursor
Provider = 'FMX'
Left = 32
Top = 32
end
object dvr1: TFDPhysSQLiteDriverLink
Left = 88
Top = 32
end
object con1: TFDConnection
Params.Strings = (
'DriverID=SQLite')
Connected = True
LoginPrompt = False
Left = 144
Top = 32
end
object loc1: TFDLocalSQL
Connection = con1
Active = True
Left = 200
Top = 32
end
object rsc1: TRESTClient
Accept = 'application/json, text/plain; q=0.9, text/html;q=0.8,'
AcceptCharset = 'utf-8, *;q=0.8'
BaseURL =
'https://me6hwinr2k.execute-api.ap-southeast-1.amazonaws.com/v0/d' +
'bqueries?item-var=9&qty=25'
Params = <>
Left = 32
Top = 112
end
object rsq1: TRESTRequest
Client = rsc1
Params = <>
Response = rsp1
SynchronizedEvents = False
Left = 32
Top = 176
end
object rsp1: TRESTResponse
ContentType = 'application/json'
Left = 32
Top = 240
end
object rsd1: TRESTResponseDataSetAdapter
Active = True
Dataset = mtb1
FieldDefs = <>
Response = rsp1
Left = 32
Top = 304
end
object mtb1: TFDMemTable
Active = True
FieldDefs = <
item
Name = 'Category'
DataType = ftWideString
Size = 255
end
item
Name = 'ID'
DataType = ftWideString
Size = 255
end
item
Name = 'Item'
DataType = ftWideString
Size = 255
end
item
Name = 'Qty'
DataType = ftWideString
Size = 255
end
item
Name = 'Container'
DataType = ftWideString
Size = 255
end
item
Name = 'Size'
DataType = ftWideString
Size = 255
end
item
Name = 'Ex temporibus dolore consequatur.'
DataType = ftWideString
Size = 255
end
item
Name = 'Et cum aut est nostrum...'
DataType = ftWideString
Size = 255
end
item
Name = 'Sequi quibusdam eum.'
DataType = ftWideString
Size = 255
end>
IndexDefs = <>
FetchOptions.AssignedValues = [evMode]
FetchOptions.Mode = fmAll
ResourceOptions.AssignedValues = [rvSilentMode]
ResourceOptions.SilentMode = True
UpdateOptions.AssignedValues = [uvCheckRequired, uvAutoCommitUpdates]
UpdateOptions.CheckRequired = False
UpdateOptions.AutoCommitUpdates = True
StoreDefs = True
Left = 32
Top = 368
end
end
FMX 程序
unit Main;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
FireDAC.UI.Intf, FireDAC.FMXUI.Wait, FireDAC.Stan.ExprFuncs,
FireDAC.Phys.SQLiteDef, FireDAC.Stan.Intf, FireDAC.Stan.Option,
FireDAC.Stan.Error, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool,
FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.SQLite, Data.DB,
FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, REST.Types,
FMX.Controls.Presentation, FMX.StdCtrls, FireDAC.Comp.DataSet,
FireDAC.Comp.Client, REST.Response.Adapter, REST.Client, Data.Bind.Components,
Data.Bind.ObjectScope, FireDAC.Phys.SQLiteVDataSet, FireDAC.Comp.UI,
FMXTee.Control, FMXTee.Grid, FMX.Layouts;
type
TForm9 = class(TForm)
cur1: TFDGUIxWaitCursor;
dvr1: TFDPhysSQLiteDriverLink;
con1: TFDConnection;
loc1: TFDLocalSQL;
rsc1: TRESTClient;
rsq1: TRESTRequest;
rsp1: TRESTResponse;
rsd1: TRESTResponseDataSetAdapter;
mtb1: TFDMemTable;
btn1: TButton;
aniSearchProcess: TAniIndicator;
lyt1: TLayout;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form9: TForm9;
tgd1: TTeeGrid;
implementation
{$R *.fmx}
procedure TForm9.btn1Click(Sender: TObject);
var
i, CanvassItemId, e : Integer;
begin
aniSearchProcess.Visible := True;
aniSearchProcess.Enabled := True;
{$IFDEF MSWINDOWS}
Application.ProcessMessages;
{$ENDIF}
{$IF DEFINED(iOS) or DEFINED(ANDROID)}
Application.HandleMessage;
{$ENDIF}
FreeAndNil(tgd1); //free old grid
//create new grid
tgd1 := TTeeGrid.Create(lyt1);
With tgd1 do
begin
Parent := lyt1;
Align := TAlignLayout.Client;
Margins.Top := 5;
Margins.Left := 5;
Margins.Right := 5;
Margins.Bottom := 5;
ScrollBars.Visible := True;
Header.Format.Font.Size := 11;
Cells.Format.Font.Size := 11;
TabOrder := 0;
ScrollBars.Visible := False;
end;
con1.StartTransaction;
try
//define the API here for duplicate/update, initial click and subsequent clicks
rsc1.BaseURL := 'https://0rgvn0s0gk.execute-api.ap-southeast-1.amazonaws.com/v0/dbqueries?item-var=1&qty=10';
rsq1.Execute;
rsd1.Active := True;
mtb1.Active;
tgd1.DataSource := mtb1;
tgd1.Enabled := True;
// adjust the column properties dynamically
with tgd1 do
begin
for i := 0 to Columns.Count -1 do
begin
if i = 0 then
begin
Columns[i].Visible := False; // category column
end
else if (i = 1) then
begin
Columns[i].Visible := False; // id column
end
else if (i = 2) then
begin
Columns[i].Width.Value := 120; // item column
end
else if (i = 3) then
begin
Columns[i].Width.Value := 30; // qty column
end
else if (i = 4) then
begin
Columns[i].Width.Value := 50; // container column
end
else if (i = 5) then
begin
Columns[i].Width.Value := 50; // size column
end
else
begin
Columns[i].Width.Value := 50; // subsequent random columns
end;
end;
end;
finally
con1.Commit;
end;
aniSearchProcess.Visible := False;
aniSearchProcess.Enabled := False;
{$IFDEF MSWINDOWS}
Application.ProcessMessages;
{$ENDIF}
{$IF DEFINED(iOS) or DEFINED(ANDROID)}
Application.HandleMessage;
{$ENDIF}
end;
end.
您在這里面臨的問題是,由於 ARC 在 Delphi 中的工作方式,您的TTeeGrid
並沒有真正被破壞。
這是為什么?
一旦您將 Parent 設置為tgd1
組件, tgd1
的引用就會添加到lyt1
Controls 集合中,該集合列出了所有子組件。 所以當你調用FreeAndNil(tgd1);
您只從全局變量tgd1
釋放對TTeeGrid
對象的引用,但布局控件集合中的引用仍然存在。 並且由於您的TTeeGrid
引用計數尚未達到零,因此該對象不會被銷毀。
所以不要使用:
FreeAndNil(tgd1);
你需要使用:
tgd1.DisposeOf;
tgd1 := nil;
這確保了你的TTeeGrid
對象的析構函數被執行而不管對象引用計數,這反過來通知布局你的TTeeGrid
對象正在被破壞,因此它需要從布局控件集合中刪除,從而允許TTeeGrid
對象引用計數達到零.
事實上,您應該使用DisposeOf
在運行時銷毀任何組件。
我建議您在如何在 Android / iOS 中釋放組件中閱讀有關此主題的更多信息
編輯 此問題僅在使用 ARC 的 Android 和 iOS 等移動平台上遇到。 在 Windows 上,您的代碼可以正常工作。 這可能是其他人無法重現您的問題的原因。
另請注意,由於在 Delphi 10.4 ARC 中已刪除,您的代碼也應該可以工作。 但我猜你沒有使用最新版本的 Delphi。
您可能希望編輯問題並包含您的 Delphi 版本以改進此問題,因為所使用的 Delphi 版本會影響問題的答案。
坦率地說,我懷疑這里是否有人可以解決您的問題,因為其他人無法真正重現它,因為我們無法訪問您的 REST 源。 相反,我建議您回溯到我在此處回答您之前關於將 TTeeGrid 與 FDMemTable 一起使用的問題。 我建議這樣做的原因是因為它提供了一種對兩個組件進行測試/基准測試的方法,該方法相當獨立,並且不依賴(對其他人)訪問您的 REST 源。 您可以使用如下代碼來調查您報告的速度下降是否與 TTeeGrid 的重復創建/釋放有關(如果是的話,我會感到驚訝)。
procedure TForm1.FormCreate(Sender: TObject);
var
AField : TField;
begin
AField := TWideStringField.Create(Self);
AField.FieldName := 'ID';
AField.Size := 255;
AField.FieldKind := fkData;
AField.DataSet := FDMemTable1;
{ repeat for other fields}
FDMemTable1.CreateDataSet;
{ insert test data using FDMemTable1.InsertRecord in a loop}
{ repeat the following to see if TTeeGrid really slows down be repeated creation/freeing}
{ create TTeeGrid1 here }
{ connect FDMemTable1 to TTeeGrid1 here}
{ TTeeGrid1.Free }
{ until done }
end;
在運行時創建 TTeeGrid 會累積開銷,從而在某些時候降低性能。
為了解決這個問題,我在運行時刪除了 TTeeGrid 的創建和釋放,相反,我在設計時放置了 TTeeGrid 可視化組件,並在每次由新數據集觸發時通過啟用為 true 或 false 的屬性刷新其連接和API提供的結構。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.