Delphi THashedStringList在查找项目时更具性能

Delphi THashedStringList在查找项目时更具性能,delphi,delphi-10-seattle,Delphi,Delphi 10 Seattle,我在维护的应用程序中发现了一个性能瓶颈,其中使用了一种奇怪的技术来本地化用户界面 名称-值对存储在一个相当大的THashedStringList中,所有对的调用都会给出瓶颈(探查器结果) THashedStringList.IndexOfName 及 不知何故,我希望有一个更快的类,能够以某种方式使用类似的签名(indexOfName和valuefromfindex),这样我就可以在不重写这个奇怪但有效的本地化机制的情况下实现性能改进。我想这段代码最初是用Delphi2009编写的,但现在我有

我在维护的应用程序中发现了一个性能瓶颈,其中使用了一种奇怪的技术来本地化用户界面

名称-值对存储在一个相当大的
THashedStringList
中,所有对的调用都会给出瓶颈(探查器结果)

THashedStringList.IndexOfName

不知何故,我希望有一个更快的类,能够以某种方式使用类似的签名(
indexOfName
valuefromfindex
),这样我就可以在不重写这个奇怪但有效的本地化机制的情况下实现性能改进。我想这段代码最初是用Delphi2009编写的,但现在我有了西雅图


谢谢。

我不能在这里发布代码(只是界面),因为它太大了,但是如果你使用alcinoe(),你会有一组类似TStringlist的组件,特别是一个名为TALHashedStringList的组件,它的工作原理与THashedStringList完全相同,但在内部使用的是Tdictionary(因此,现在TALHashedStringList.IndexOfName和TALHashedStringList.ValueFromIndex占用的时间必须为null)

{-------------------------------------------}
TALHashedStringList=类(TALStrings)
私有的
FNodeList:TObjectList;

FDictionary:TALObjectDictionary

我不能在这里发布代码(只是界面),因为它太大了,但是如果你使用alcinoe(),你会有一组类似于TStringlist的组件,特别是一个叫做TALHashedStringList的组件,它的工作原理与THashedStringList完全相同,但在内部使用的是Tdictionary(因此,现在TALHashedStringList.IndexOfName和TALHashedStringList.ValueFromIndex占用的时间必须为null)

{-------------------------------------------}
TALHashedStringList=类(TALStrings)
私有的
FNodeList:TObjectList;

FDictionary:TALObjectDictionary

最明显的尝试是
TDictionary
。尽管我怀疑唯一的区别将是散列代码。可能
TDictionary
使用更快的散列代码。没有一些具体细节,例如数据、计时、预期性能级别,我们只能猜测。你应该做的是花更多的钱是时候提取一个能证明你的问题的列表了。这需要你付出努力,但会有回报。这不需要任何证据-众所周知,如果你有很多项,THashedStringList就是垃圾,因为它只是为了更快地查找一个很少有数千个节和值的TMemIniFile。它使用一个带有修正的hashmapd大小为256个桶,因此会产生大量碰撞,并很快将其转化为O(n)256个桶!糟糕。我没有深入挖掘,很难预测这样的无能。所以,是的,首先尝试
TDictionary
THashedStringList.Create()
takes具有默认为256个存储桶的
Size
参数。因此,检查您有多少字符串并相应地设置大小可能会容易得多。我假设本地化
THashedStringList
在初始化后不会更改?如果更改,则会出现更大的问题…每次字符串更改,整个ta都会更改ble需要重新刷新!@Craigyong
THashedStringList
不会将桶大小带到任何地方。大小被传递到
TStringHash。创建一个默认值为256的
UpdateNameHash
UpdateValueHash
中硬编码的
TStringHash-查看代码。显然要尝试的是
TDictionary
。虽然我怀疑唯一的区别是哈希代码。也许代码> T字典[/COD]使用更快的哈希代码。没有具体的细节,例如数据、时序、预期的性能水平,我们可以猜测。你应该花时间来提取一个演示你的问题。这将需要努力在你的PAR。t、 但是会有一个奖励。这不需要任何证据-众所周知,如果你有很多项目,THashedStringList就是垃圾,因为它只是为了更快地查找一个几乎没有数千个节和值的TMemIniFile。它使用一个固定大小为256个bucket的hashmap,因此会产生大量冲突,并很快将其转换为O(n)256桶!糟糕透了。我没挖那么深,很难预料会有这样的无能。所以,是的,先试试
TDictionary
THashedStringList.Create()
takes具有默认为256个存储桶的
Size
参数。因此,检查您有多少字符串并相应地设置大小可能会容易得多。我假设本地化
THashedStringList
在初始化后不会更改?如果更改,则会出现更大的问题…每次字符串更改,整个ta都会更改ble需要重新格式化!@Craigyong
THashedStringList
不会将存储桶大小带到任何地方。大小会传递给
TStringHash。创建一个默认值为256的
UpdateNameHash
UpdateValueHash
硬编码。查看代码。这是一个非常糟糕的主意。直接使用字典d不要再试图把所有东西都放在TStrings衍生品中,继续使用这个蹩脚的界面。放手吧。使用字典。而且,你没有提到任何关于性能的东西。为什么这个主意不好?这正是LaBracca所要求的!他不想重建所有东西,而是想要一个与THashedStringList在w对中具有相同界面的东西对于性能!很抱歉,在TString中使用Tdictionary是一个绝妙的主意,因为你不能在Tdictionary中使用TString做所有你能做的事情(比如订购物品),反之亦然,你不能在Tstringlist中使用Tdictionary做任何你能用Tdictionary做的事情(比如像地狱一样快的IndexOfName)。因此,将这两个世界融合在一起是非常好的。当然,这也取决于需要(如果你需要这两个世界)!@DavidHeffernan,关于性能,我说,TALHashedStringList.IndexOfName的时间将为空(就像做myarray[x],它将立即生效)开销非常小,事实上,您正在维护两个列表:THashedStringList.ValueFromIndex
  {----------------------------------}
  TALHashedStringList = class(TALStrings)
  private
    FNodeList: TObjectList<TALHashedStringListDictionaryNode>;
    FDictionary: TALObjectDictionary<ansiString, TALHashedStringListDictionaryNode>;
    FDuplicates: TDuplicates;
    FOnChange: TNotifyEvent;
    FOnChanging: TNotifyEvent;
    FOwnsObject: Boolean;
    FCaseSensitive: boolean;
    procedure ExchangeItems(Index1, Index2: Integer);
    procedure QuickSort(L, R: Integer; SCompare: TALHashedStringListSortCompare);
    procedure SetCaseSensitive(const Value: Boolean);
    function GetCaseSensitive: Boolean;
    Function ExtractNameValue(const S: AnsiString; var Name, Value: AnsiString): Boolean;
    procedure SetDuplicates(const Value: TDuplicates);
    function CreateDictionary(ACapacity: integer; aCaseSensitive: boolean): TALObjectDictionary<ansiString, TALHashedStringListDictionaryNode>;
  protected
    function GetName(Index: Integer): AnsiString; override;
    function GetStrictName(Index: Integer): AnsiString; override; // [added from Tstrings]
    function GetValue(const Name: AnsiString): AnsiString; override;
    procedure SetValue(const Name, Value: AnsiString); override;
    function GetValueFromIndex(Index: Integer): AnsiString; override;
    procedure SetValueFromIndex(Index: Integer; const Value: AnsiString); override;
    procedure SetPersistentValue(const Name, Value: AnsiString); override; // [added from Tstrings]
    procedure SetPersistentValueFromIndex(Index: Integer; const Value: AnsiString); override; // [added from Tstrings]
    procedure Changed; virtual;
    procedure Changing; virtual;
    function Get(Index: Integer): AnsiString; override;
    function GetCount: Integer; override;
    function GetObject(Index: Integer): TObject; override;
    function GetTextStr: AnsiString; override;
    procedure Put(Index: Integer; const S: AnsiString); override;
    procedure PutObject(Index: Integer; AObject: TObject); override;
    procedure SetCapacity(NewCapacity: Integer); override;
    procedure SetUpdateState(Updating: Boolean); override;
    procedure InsertItem(Index: Integer; const Name, Value: AnsiString; AObject: TObject); overload; virtual;
    procedure InsertItem(Index: Integer; const S: AnsiString; AObject: TObject); overload; virtual;
    procedure AssignTo(Dest: TPersistent); override; //[added from Tstrings]
    procedure init(OwnsObjects: Boolean; ACapacity: Integer); virtual; //[added from TStringList]
  public
    constructor Create; overload; override;
    constructor Create(OwnsObjects: Boolean); reintroduce; overload;
    constructor Create(ACapacity: Integer); reintroduce; overload; //[added from Tstrings]
    constructor Create(OwnsObjects: Boolean; ACapacity: Integer); reintroduce; overload; //[added from Tstrings]
    destructor Destroy; override;
    function Add(const S: AnsiString): Integer; override;
    function AddObject(const S: AnsiString; AObject: TObject): Integer; override;
    function AddNameValue(const Name, Value: AnsiString): Integer; override; // [added from Tstrings]
    function AddNameValueObject(const Name, Value: AnsiString; AObject: TObject): Integer; override; // [added from Tstrings]
    procedure Assign(Source: TPersistent); override;
    procedure Clear; override;
    procedure Delete(Index: Integer); override;
    function  ExtractObject(Index: Integer): TObject; overload; virtual;
    procedure Exchange(Index1, Index2: Integer); override;
    function IndexOf(const S: AnsiString): Integer; override;
    function IndexOfName(const Name: AnsiString): Integer; override; // [added from TStringList]
    procedure Insert(Index: Integer; const S: AnsiString); override;
    procedure InsertObject(Index: Integer; const S: AnsiString; AObject: TObject); override;
    procedure InsertNameValue(Index: Integer; const Name, Value: AnsiString); override; // [added from Tstrings]
    procedure InsertNameValueObject(Index: Integer; const Name, Value: AnsiString; AObject: TObject); override; // [added from Tstrings]
    procedure Move(CurIndex, NewIndex: Integer); override;
    procedure CustomSort(Compare: TALHashedStringListSortCompare); virtual;
    property Duplicates: TDuplicates read FDuplicates write SetDuplicates;
    property CaseSensitive: Boolean read GetCaseSensitive write SetCaseSensitive;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
    property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
    property OwnsObjects: Boolean read FOwnsObject write FOwnsObject;
  end;