在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
原始连接:http://rvelthuis.blogspot.tw/2018/01/strings-on-other-platforms-than-32-bit.html Strings too slow outside WIN32?In a recent debate I had it was said that strings in the Win64 runtime are too slow to be useful. That is, in my opinion, a gross exaggeration. It is true that the Win32 runtime library (RTL) has benefited a lot from the work of the FastCode project, usually with routines in extremely clever assembler. For all other platforms, often the routines are in plain Object Pascal, so no assembler is being used. Also, far fewer routines have been replaced by clever implementations. One very obvious example of this is the The implementation for If you look at the sources in For fun, I took the code for the But even that can be improved upon. I wrote three implementations of my own routine, one for CodeHere is the code for my function RVPosExA(const Needle, Haystack: AnsiString; Offset: Integer = 1): Integer; type PUInt32 = ^UInt32; PUInt16 = ^UInt16; {$IFNDEF CPU32BITS} var LNeedleTip: UInt32; PNeedle: PAnsiChar; PHaystack, PEnd: PAnsiChar; LLenNeedle: Integer; LCmpMemOffset: Integer; {$ENDIF} begin {$IFDEF CPU32BITS} // FastCode (asm) implementation. Result := System.Pos(Needle, Haystack, Offset); {$ELSE} if Offset - 1 + Length(Needle) > Length(Haystack) then Exit(0); Result := 0; PHaystack := PAnsiChar(Haystack) + Offset - 1; PEnd := PHaystack + Length(Haystack) - Length(Needle) + 1; case Length(Needle) of 0: Exit(0); 1: begin LNeedleTip := PByte(Needle)^; while PHaystack < PEnd do if PByte(PHaystack)^ = LNeedleTip then Exit(PHaystack - PAnsiChar(Haystack) + 1) else Inc(PHaystack); Exit(0); end; 2: begin LNeedleTip := PUInt16(Needle)^; while PHaystack < PEnd do if PUInt16(Haystack)^ = LNeedleTip then Exit(PHayStack - PAnsiChar(Haystack) + 1) else Inc(PHaystack); Exit(0); end; 3: begin LNeedleTip := PUInt32(Needle)^; // if Needle is length 3, then top byte // is the #0 terminator while PHaystack < PEnd do if ((PUInt32(Haystack)^ xor LNeedleTip) and $FFFFFF) = 0 then Exit(PHaystack - PAnsiChar(Haystack) + 1) else Inc(PHaystack); Exit(0); end; 4: begin LNeedleTip := PUInt32(Needle)^; while PHaystack < PEnd do if PUInt32(Haystack)^ = LNeedleTip then Exit(PHaystack - PAnsiChar(Haystack) + 1) else Inc(PHaystack); Exit(0); end; else begin LCmpMemOffset := SizeOf(UInt32) div SizeOf(AnsiChar); PNeedle := PAnsiChar(Needle) + LCmpMemOffset; LLenNeedle := Length(Needle) - LCmpMemOffset; LNeedleTip := PUInt32(Needle)^; while PHaystack < PEnd do if (PUInt32(PHaystack)^ = LNeedleTip) and CompareMem(PHaystack + LCmpMemOffset, PNeedle, LLenNeedle) then Exit(PHaystack - PAnsiChar(Haystack) + 1) else Inc(PHaystack); end; end; {$ENDIF} end; As you can see, under Win32, it simply jumps to TimingHere is a slightly reformatted output of a test program (I put the WIN32 and the WIN64 columns beside each other, to save space): Different versions of Pos(Needle, Haystack: <sometype>; Offset: Integer): Integer where <sometype> is UnicodeString, AnsiString or TBytes Testing with Haystack lengths of 50, 200, 3000, 4000 and 300000 and Needle lengths of 1, 3, 8 and 20 5 * 4 * 2000 = 40000 loops WIN64 WIN32 UnicodeString UnicodeString ------------- ------------- System.Pos: 2428 ms System.Pos: 1051 ms StrUtils.PosEx: 2258 ms StrUtils.PosEx: 1070 ms RVPosExU: 1071 ms RVPosExU: 1050 ms AnsiString AnsiString ---------- ---------- System.Pos: 4956 ms System.Pos: 1046 ms AnsiStrings.PosEx: 4959 ms AnsiStrings.PosEx: 1051 ms OrgPosA: 5129 ms OrgPosA: 5712 ms PosUModForA: 1958 ms PosUModForA: 3744 ms RVPosExA: 1322 ms RVPosExA: 1086 ms TBytes TBytes ------ ------ RVPosEXB: 998 ms RVPosEXB: 2754 ms Haystack: random string of 500000000 ASCII characters or bytes Needle: last 10 characters of Haystack = 'WRDURJVDFA' WIN64 WIN32 UnicodeString UnicodeString ------------- ------------- System.Pos: 847 ms System.Pos: 421 ms Strutils.PosEx: 827 ms Strutils.PosEx: 414 ms RVPosExU: 421 ms RVPosExU: 438 ms AnsiString AnsiString ---------- ---------- System.Pos: 1735 ms System.Pos: 428 ms AnsiStrings.PosEx: 1831 ms AnsiStrings.PosEx: 428 ms OrgPosA: 1749 ms OrgPosA: 2687 ms PosUModForA: 708 ms PosUModForA: 1525 ms RVPosExA: 368 ms RVPosExA: 423 ms RvPosExA(,,Offset): 200 ms RvPosExA(,,Offset): 220 ms TBytes TBytes ------ ------ RVPosExB(TBytes): 385 ms RVPosExB(TBytes): 1095 ms The routines As you can see, the I didn't check, but it is well possible that one of the plain Pascal versions of the FastCode project is faster. But for me, this implementation is a start and proof, that with a few simple optimizations string routines could be made faster. Perhaps, one day, Embarcadero will adopt more of the plain Pascal code from the FastCode project. The code for the routines and the program that produces the output above can be downloaded from my website. |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论