delphi 将不同序数类型的数组集中转换,而不是逐个转换元素

23c0lvtd  于 2023-02-12  发布在  其他
关注(0)|答案(1)|浏览(96)

只是好奇:我正在寻找一个理论问题的解决方案,以优化数据结构在应用程序中的使用。
假设有以下类型(如果有问题,当前使用DXE7):

type
  TMyType1 = 0..4294967295; 
  TMyType2 = 0..65535;
  TMyArrayType1 = array of TMyType1;
  TMyArrayType2 = array of TMyType2;

我们现在需要做的是将TMyArrayType2类型的数组“转换”为TMyArrayType1。为什么?可能是为了向后或向前兼容的原因,也可能是为了尽可能地减少数据大小,但是在我们应用程序的大多数方法中只处理一种类型(这里是:TMyType1),以避免重载许多方法来处理这两种类型,等等。比方说,两种数组类型都有各自的优点,因此不能用另一种类型替换。
由于TMyType2的所有可能值都拟合到TMyType1中,我们可以做如下操作:

procedure Convert(const[ref] ASource: TMyArrayType2; var ADest: TMyArrayType1);
var
   ALen, i: Integer;
begin
     ALen:= Length(ASource);
     SetLength(ADest, ALen);
     FOR i:=0 TO ALen-1 DO
      begin
           ADest[i]:= ASource[i];
      end;
end;

编译,但是我们可以想象,这对于大数组来说可能非常慢,而且在经常使用时(可能在循环中,等等),甚至对于较小的数组,也可能是一个性能问题。
那么有没有办法加快速度呢?
在最好的情况下,我们可以“成批“”移动”数据(就像System.Move方法一样),而不是一个一个地设置。但是由于TMyType1TMyType2的大小不同,我无法想象有什么方法可以处理这个问题。这意味着复制数据的“模式(阅读2个字节并只使用第一个字节)就像复制图像中的“遮罩”区域,而不是逐像素复制,这不是很好吗?)
我想了很多,并放弃了一些想法,先将数据“移动”(使用System.Move)到一个压缩记录数组中,每个记录都包含TMyArrayType1(和比?)的低位和高位字节,我被卡住了,所以我认为这个问题没有真实的的解决方案,现在我想知道你们中是否有人能告诉我我错了。

zkure5ic

zkure5ic1#

简单时间测量的小测试。汇编程序每轮处理4个元素。

procedure WordsToDwords(pw, pd: Pointer; const Size: Integer);
//x86 32 bit, register calling convention - three parameters in EAX, EDX, ECX
asm
  pxor XMM2, XMM2
  shr ecx, 2  //size should be divisible by 4
  @@cycle:
    movq XMM1, [eax]
    punpcklwd XMM1, XMM2 //words to dwords
    movdqu [edx], XMM1
    add eax, 8        // inc pointers
    add edx, 16
    loop @@cycle
end;

var
  w: TArray<Word>;
  d: TArray<DWord>;
  n, i:  Integer;
  t1, t2, t3: DWord;    

begin
  n := 250000000;
  SetLength(w, n);
  SetLength(d, n);
  for i := 0 to n-1 do
    w[i] := i and $FFFF;
  t1 := GetTickCount();
  for i := 0 to n-1 do
     d[i] := w[i];
  t2 := GetTickCount();
  WordsToDwords(@w[0], @d[0], n);
  t3 := GetTickCount();
  Memo1.Lines.Add((t2-t1).ToString +' ' + (t3-t2).ToString);
  for i := 255 to 257 do  //to check
    memo1.Lines.Add(d[i].ToString);
end;

此代码将500兆字节的字解压缩为1 GB的双字。
在内存吞吐量为12 GB/秒(Haswell Xeon 3.1 GHz,单通道DDR3-1600内存)的计算机上:调试模式exe为分配方法和asm解包提供了516/219 ms,发布模式exe为两种方法提供了约220 ms-注意7 GB/秒的处理,因此内存限制了速度(从不同地址读写小块)
在内存吞吐量为45 GB/秒(锐龙5600 G,双通道DDR4-3200)的机器上:调试模式exe为分配方法和asm解包提供227/119 ms,发布模式exe为两种方法提供108/78 ms,代码处理14/18 GB/秒,因此内存再次限制了速度。
似乎每秒7-14 GB不是真实的的瓶颈

相关问题