Delphi 如何有效地交换2 TB变量?
我有2 TB的变量:Delphi 如何有效地交换2 TB变量?,delphi,Delphi,我有2 TB的变量: A: Tbytes; B: Tbytes; 现在我想这样交换 tmp := A; A := B; B := tmp; 但我不确定这是否是最有效的方法,特别是对于写时复制(如果它与字符串相同) 也许是这样的: Tmp := Pointer(a); pointer(a) := pointer(b); pointer(b) := Tmp ; 动态数组没有写时拷贝,但如果有,那也没关系,因为没有写入任何内容(数组的内容) 您的方式是最有效的
A: Tbytes;
B: Tbytes;
现在我想这样交换
tmp := A;
A := B;
B := tmp;
但我不确定这是否是最有效的方法,特别是对于写时复制(如果它与字符串相同)
也许是这样的:
Tmp := Pointer(a);
pointer(a) := pointer(b);
pointer(b) := Tmp ;
动态数组没有写时拷贝,但如果有,那也没关系,因为没有写入任何内容(数组的内容) 您的方式是最有效的:只复制引用,并更新一些引用计数 使用指针的方法会稍微更有效一些(无需重新计数),但也有点风险。您可以这样做,因为最终,两个数组的引用计数应该与以前相同。如果在交换过程中没有任何东西可以访问(本地)引用,那么这应该无关紧要 更新 如果您按照David的建议执行,即将此代码放在单独的过程中,那么使用本地
Temp
变量或外部变量并不重要。但是使用指针
强制转换的交换速度是使用t字节
的正常交换速度的10倍(十倍)
请参阅我对另一个答案的评论:无论是使用外部变量还是本地
Temp
变量,它们的速度几乎相同。我测量了一个本地Temp
变量的平均值为6512毫秒,外部Temp
变量的平均值为6729毫秒,使用指针的平均值为589毫秒。我以不同的顺序做了几次测试,以消除任何计时错误。交换空(nil
)数组时会有时间上的差异,但我认为这些都没有多大关系,因为已经有人回答说,在彼此之间交换两个t字节的代码是最有效的。因此,我在这里的帖子并不是对你的问题的回答,相反,我只是想提醒你,如果不恰当地使用此代码,那么调用此代码的代码实际上会导致性能损失,那么可能会破坏性能 现在,基于这样一个事实,您甚至在考虑这样一小段代码的性能,我猜您可能正计划在一个大循环中执行这段代码,在这个循环中,这段代码的性能稍有提高可能会对应用程序的整体性能产生重大影响。如果您多次调用这段代码,我敢打赌您根本不会担心它的性能,因为它对整个应用程序的性能影响微乎其微 因此,如果您按照David的建议将此代码放入一个过程中,我猜您可能会编写如下内容:
procedure SwapBytes(var A,B: TBytes);
var Temp: Tbytes;
begin
Temp := A;
A := B;
B := Temp;
end;
没什么特别的。但问题是,每次在循环中调用此过程时,应用程序都必须在进入过程时初始化(为其分配内存)该局部变量,然后在退出上述过程时完成(释放内存)。为什么这么糟糕?因为分配od释放内存比实际写入或读取已经分配的内存慢得多
那么,如何避免这个问题呢?您可以在过程外部初始化Temp变量,并将其作为附加参数传递给过程。性能增益可以是显著的,这种方式可以是显著的
这里是我的测试示例,我使用了这两种方法并测量了它们的性能
//Basic procedure for swapping two TBytes values between each other
//It has local variable Temp of TBytes type which is automatically created when
//entering the procedure and released when exiting the procedure
procedure SwapBytesLocalTempVariable(var A,B: TBytes);
var Temp: TBytes;
begin
Temp := A;
A := B;
B := Temp;
end;
//Same as above bit this procedure does not contain any local variable so you
//need to pas the Temp variable as an additional input parameter
procedure SwapBytesExternalTempVariable(var A,B,Temp: TBytes);
begin
Temp := A;
A := B;
B := Temp;
end;
//Quick procedure for testing
procedure TForm1.Button1Click(Sender: TObject);
var A,B: TBytes;
I: Integer;
SW: TStopWatch;
Temp: TBytes;
begin
//Calling first procedure with local temp variable in a loop many times can be
//quite slow because your program needs to initialize and release that local
//variable in each loop cycle.
SW := TStopWatch.Create;
SW.Start;
for I := 0 to 100000000 do
begin
SwapBytesLocalTempVariable(A,B);
end;
SW.Stop;
Memo1.Lines.Add(Format('Swap bytes with local variable: %f',[SW.Elapsed.TotalMilliseconds]));
//Calling second procedure which does not have local temp variable and passing
//the temp variable as additional parameter is much quicker because this way
//the Temp variable isn't initialized and then released in each loop cycle but
//instead we created (initialized) it outside the loop (out OnClick method of
//TButton and is therefore being reused in each loop cycle.
SW := TStopWatch.Create;
SW.Start;
for I := 0 to 100000000 do
begin
SwapBytesExternalTempVariable(A,B,Temp);
end;
SW.Stop;
Memo1.Lines.Add(Format('Swap bytes with external variable: %f',[SW.Elapsed.TotalMilliseconds]));
end;
现在您可以看到,这两种方法的性能差异非常显著。在我的测试过程中,使用局部变量调用第一个过程大约花费了1800毫秒(几乎两秒),而调用第二个过程,其中我使用临时变量作为附加参数,只花费了800毫秒。现在,这是上述两种方法之间的一秒性能增益
无论如何,一般建议是尽量减少内存分配的数量,并尽可能地重用变量。如果您有大量衡量的性能,为什么您认为您会有性能问题?理论上,您应该只优化瓶颈代码。这段代码是一个瓶颈吗?你的意见是少数。专业程序员公认的原则是“过早优化是万恶之源”。你在这里很好地说明了我的观点。缺乏理解,加上未对绩效进行适当衡量而做出的决策。这是典型的过早优化领域。我还想知道为什么您一直在谈论写时复制,而这种复制不适用于这样的交换,即使对于实现COW的类型也是如此。将变量的类型更改为字符串,则仍然没有COW。所以,是的,你学到了一些东西,但在要学的三个课程中,似乎只有一个已经深入人心。也就是说,动态数组没有COW,讽刺的是,这个教训在这里没有影响!其他需要了解的事情是,当字符串内容被修改时,COW for strings适用,并且优化应该只使用具体的真实世界性能度量来指导。是的:)这种分配/取消分配非常损害性能,当我们谈论数百万次循环时,这真的很重要@洛基:你在循环中交换数百万兆字节?为什么?如果使用指针强制转换和局部指针变量会发生什么?无法在此iPad上进行测试。@RudyVelthuis,因为我使用带有文件\u FLAG\u NO\u缓冲区的Windows api writefile来执行一些恢复过程,这样缓冲区(即使在内存中,也不仅仅是写指针)需要与扇区对齐:(当我处理相当大的文件(+1 TB)时,我需要无数次交换TB缓冲区:(…我还没有尝试使用局部指针变量,我将尝试看看它是否有变化,如果您需要扇区对齐,好吗