Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
88 views
in Technique[技术] by (71.8m points)

.net - Array.Copy vs Buffer.BlockCopy

Array.Copy and Buffer.BlockCopy both do the same thing, but BlockCopy is aimed at fast byte-level primitive array copying, whereas Copy is the general-purpose implementation. My question is - under what circumstances should you use BlockCopy? Should you use it at any time when you are copying primitive type arrays, or should you only use it if you're coding for performance? Is there anything inherently dangerous about using Buffer.BlockCopy over Array.Copy?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Prelude

I'm joining the party late, but with 32k views, it's worth getting this right. Most of the microbenchmarking code in the posted answers thus far suffer from one or more severe technical flaws, including not moving memory allocations out of the test loops (which introduces severe GC artifacts), not testing variable vs. deterministic execution flows, JIT warmup, and not tracking intra-test variability. In addition, most answers did not test the effects of varying buffer sizes and varying primitive types (with respect to either 32-bit or 64-bit systems). To address this question more comprehensively, I hooked it up to a custom microbenchmarking framework I developed that reduces most of the common "gotchas" to the extent possible. Tests were run in .NET 4.0 Release mode on both a 32-bit machine and a 64-bit machine. Results were averaged over 20 testing runs, in which each run had 1 million trials per method. Primitive types tested were byte (1 byte), int (4 bytes), and double (8 bytes). Three methods were tested: Array.Copy(), Buffer.BlockCopy(), and simple per-index assignment in a loop. The data is too voluminous to post here, so I will summarize the important points.

The Takeaways

  • If your buffer length is about 75-100 or less, an explicit loop copy routine is usually faster (by about 5%) than either Array.Copy() or Buffer.BlockCopy() for all 3 primitive types tested on both 32-bit and 64-bit machines. Additionly, the explicit loop copy routine has noticeably lower variability in performance compared to the two alternatives. The good performance is almost surely due to locality of reference exploited by CPU L1/L2/L3 memory caching in conjunction with no method call overhead.
    • For double buffers on 32-bit machines only: The explicit loop copy routine is better than both alternatives for all buffer sizes tested up to 100k. The improvement is 3-5% better than the other methods. This is because the performance of Array.Copy() and Buffer.BlockCopy() become totally degraded upon passing the native 32-bit width. Thus I assume the same effect would apply to long buffers as well.
  • For buffer sizes exceeding ~100, explicit loop copying quickly becomes much slower than the other 2 methods (with the one particular exception just noted). The difference is most noticeable with byte[], where explicit loop copying can become 7x or more slower at large buffer sizes.
  • In general, for all 3 primitive types tested and across all buffer sizes, Array.Copy() and Buffer.BlockCopy() performed almost identically. On average, Array.Copy() seems to have a very slight edge of about 2% or less time taken (but 0.2% - 0.5% better is typical), although Buffer.BlockCopy() did occasionally beat it. For unknown reasons, Buffer.BlockCopy() has noticeably higher intra-test variability than Array.Copy(). This effect could not be eliminated despite me trying multiple mitigations and not having an operable theory on why.
  • Because Array.Copy() is a "smarter", more general, and much safer method, in addition to being very slightly faster and having less variability on average, it should be preferred to Buffer.BlockCopy() in almost all common cases. The only use case where Buffer.BlockCopy() will be significantly better is when the source and destination array value types are different (as pointed out in Ken Smith's answer). While this scenario is not common, Array.Copy() can perform very poorly here due to the continual "safe" value type casting, compared to the direct casting of Buffer.BlockCopy().
  • Additional evidence from outside StackOverflow that Array.Copy() is faster than Buffer.BlockCopy() for same-type array copying can be found here.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...