Array.Copy बनाम Buffer.BlockCopy


124

Array.Copy और Buffer.BlockCopy दोनों एक ही काम करते हैं, लेकिन BlockCopyइसका उद्देश्य तेजी से बाइट-स्तरीय प्राइमरी सरणी कॉपी करना है, जबकि Copyसामान्य उद्देश्य कार्यान्वयन है। मेरा सवाल है - आपको किन परिस्थितियों में उपयोग करना चाहिए BlockCopy? क्या आपको किसी भी समय इसका उपयोग करना चाहिए जब आप आदिम प्रकार सरणियों की नकल कर रहे हैं, या क्या आपको केवल इसका उपयोग करना चाहिए यदि आप प्रदर्शन के लिए कोडिंग कर रहे हैं? वहाँ कुछ का उपयोग Buffer.BlockCopyकरने के बारे में स्वाभाविक रूप से खतरनाक है Array.Copy?


3
Marshal.Copy:-) मत भूलना । ठीक है, Array.Copyसंदर्भ प्रकार, जटिल मान प्रकार और यदि प्रकार नहीं बदलता है, तो Buffer.BlockCopyमूल्य प्रकार, बाइट सरणियों और बाइट जादू के बीच "रूपांतरण" के लिए उपयोग करें। F.ex. StructLayoutयदि आप जानते हैं कि आप क्या कर रहे हैं तो संयोजन काफी शक्तिशाली है। प्रदर्शन के लिए, यह एक अनवांटेड कॉल लगता है memcpy/ cpblkउसके लिए सबसे तेज़ है - कोड 4k.blogspot.nl/2010/10/ देखें ।
atlaste

1
मैंने कुछ बेंचमार्क टेस्ट किए byte[]। रिलीज़ संस्करण में कोई अंतर नहीं था। कभी Array.Copy- कभी , कभी-कभी Buffer.BlockCopy(थोड़ा) तेज।
Bitterblue

नया व्यापक उत्तर अभी नीचे पोस्ट किया गया है। ध्यान दें कि छोटे बफर आकार वाले मामलों में, स्पष्ट लूप की नकल आमतौर पर सबसे अच्छी होती है।
स्पेशल सॉस

मुझे नहीं लगता कि वे हमेशा एक ही काम करते हैं - आप Array.Copy का उपयोग नहीं कर सकते हैं। उदाहरण के लिए Ints की एक सरणी को बाइट्स के एक सरणी में
कॉपी करें

Array.Copyबल्कि एक विशेष संस्करण है - उदाहरण के लिए यह केवल एक ही रैंक सरणियों को कॉपी कर सकता है।
एस्ट्रोवैलर

जवाबों:


59

चूंकि पैरामीटर Buffer.BlockCopyइंडेक्स-आधारित होने के बजाय बाइट-आधारित होते हैं Array.Copy, इसलिए यदि आप उपयोग करते हैं , तो आप अपने कोड को खराब करने की अधिक संभावना रखते हैं , इसलिए मैं केवल Buffer.BlockCopyअपने कोड के प्रदर्शन-महत्वपूर्ण अनुभाग में उपयोग करूंगा।


9
पूरी तरह से सहमत हूँ। Buffer.BlockCopy के साथ त्रुटि के लिए बहुत अधिक जगह है। इसे सरल रखें, और अपने कार्यक्रम से किसी भी रस को निचोड़ने की कोशिश न करें जब तक कि आपको पता न हो कि रस कहां है (प्रोफाइलिंग)।
स्टीफन

5
यदि आप एक बाइट [] के साथ काम कर रहे हैं तो क्या होगा? क्या ब्लॉकचौपी के साथ कोई और गेटअप है?
thecoop

4
@thecoop: यदि आप एक बाइट के साथ काम कर रहे हैं [] तो शायद ब्लॉकचोपी का उपयोग करना ठीक है, जब तक कि "बाइट" की परिभाषा बाद में बाइट के अलावा किसी और चीज़ में बदल जाती है, जिसका संभवतः दूसरे हिस्सों पर काफी नकारात्मक प्रभाव पड़ेगा। आपका कोड वैसे भी। :) केवल अन्य संभावित गोटा है कि ब्लॉककॉपी सिर्फ सीधे बाइट्स करता है, इसलिए यह धीरज को ध्यान में नहीं रखता है, लेकिन यह केवल एक गैर-विंडोज मशीन पर खेलना होगा, और केवल तभी जब आप कोड को खराब कर देंगे प्रथम स्थान। इसके अलावा, अगर आप मोनो का उपयोग कर रहे हैं तो कुछ अजीब अंतर हो सकता है।
मुसैनेसिस

6
अपने स्वयं के परीक्षण में, Array.Copy () बफ़र.ब्लॉककॉपी () के प्रदर्शन में बहुत समान है। Buffer.BlockCopy 640 तत्व बाइट सरणियों से निपटने के लिए लगातार मेरे लिए 10% तेज है (जो कि मुझे सबसे ज्यादा पसंद है)। लेकिन आपको अपने स्वयं के डेटा के साथ स्वयं का परीक्षण करना चाहिए, क्योंकि यह संभवतः डेटा, डेटा प्रकार, सरणी आकार, और इसके आधार पर भिन्न होगा। मुझे ध्यान देना चाहिए कि दोनों विधियां Array.Clone () का उपयोग करने की तुलना में लगभग 3x तेज हैं, और शायद एक लूप के लिए इसे कॉपी करने की तुलना में 20x तेज है।
केन स्मिथ

3
@ केविनमिलर: उह, UInt16प्रति तत्व दो बाइट्स है। यदि आप सरणी में तत्वों की संख्या के साथ इस सरणी को ब्लॉकचॉपी में पास करते हैं, तो निश्चित रूप से केवल आधे सरणी की प्रतिलिपि बनाई जाएगी। इस ठीक से काम करने के लिए, आप तत्वों की संख्या पारित करने के लिए की आवश्यकता होगी बार प्रत्येक तत्व (2) लंबाई पैरामीटर के रूप में के आकार। msdn.microsoft.com/en-us/library/… और INT_SIZEउदाहरणों में खोजें।
मुसिगनेसिस

129

प्रस्तावना

मैं देर से पार्टी में शामिल हो रहा हूं, लेकिन 32k विचारों के साथ, यह अधिकार प्राप्त करने के लायक है। पोस्ट किए गए उत्तरों में अधिकांश माइक्रोबेनमार्किंग कोड इस प्रकार एक या एक से अधिक गंभीर तकनीकी खामियों से ग्रस्त हैं, जिसमें परीक्षण छोरों (जो गंभीर जीसी कलाकृतियों का परिचय देता है) से बाहर स्मृति आबंटन शामिल नहीं है, न कि परीक्षण बनाम बनाम नियतात्मक निष्पादन प्रवाह, जेआईटी वार्मअप, और इंट्रा-टेस्ट परिवर्तनशीलता पर नज़र नहीं रखना। इसके अलावा, अधिकांश उत्तरों ने अलग-अलग बफर आकारों और अलग-अलग आदिम प्रकारों के प्रभावों का परीक्षण नहीं किया (32-बिट या 64-बिट सिस्टम के संबंध में)। इस प्रश्न को अधिक व्यापक रूप से संबोधित करने के लिए, मैंने इसे एक कस्टम माइक्रोबैन्चमार्किंग फ्रेमवर्क के साथ जोड़ा, जिसे मैंने विकसित किया, जो कि आम "गेटा" के अधिकांश हिस्से को कम कर देता है। 32-बिट मशीन और 64-बिट मशीन दोनों पर .NET 4.0 रिलीज मोड में टेस्ट चलाए गए। परिणाम 20 से अधिक परीक्षण रन थे, जिसमें प्रत्येक रन में प्रति विधि 1 मिलियन परीक्षण थे। परीक्षण किए गए आदिम प्रकार थेbyte(1 बाइट), int(4 बाइट्स), और double(8 बाइट्स)। तीन तरीकों का परीक्षण किया गया: Array.Copy(), Buffer.BlockCopy()एक पाश में, और सरल प्रति-सूचकांक काम। यहां पोस्ट करने के लिए डेटा बहुत अधिक चमकदार है, इसलिए मैं महत्वपूर्ण बिंदुओं को संक्षेप में बताऊंगा।

तकिए

  • अपने बफर लंबाई 75-100 या उससे कम के बारे में है, तो एक स्पष्ट पाश प्रति दिनचर्या आम तौर पर तेजी से (5 के बारे में% से) या तो की तुलना में है Array.Copy()या Buffer.BlockCopy()सभी 3 आदिम 32-बिट और 64-बिट मशीनों पर परीक्षण प्रकार के लिए। अतिरिक्त रूप से, स्पष्ट लूप कॉपी रूटीन में दो विकल्पों की तुलना में प्रदर्शन में उल्लेखनीय परिवर्तनशीलता कम है। सीपीयू एल 1 / एल 2 / एल 3 मेमोरी कैशिंग द्वारा बिना किसी विधि कॉल ओवरहेड के साथ शोषण किए गए संदर्भ के स्थानीयता के कारण अच्छा प्रदर्शन लगभग निश्चित रूप से है
    • केवल 32-बिट मशीनों परdouble बफ़र्स के लिए : स्पष्ट लूप कॉपी दिनचर्या 100k तक परीक्षण किए गए सभी बफर आकारों के लिए दोनों विकल्पों से बेहतर है। अन्य तरीकों की तुलना में सुधार 3-5% बेहतर है। ऐसा इसलिए है क्योंकि देशी 32-बिट चौड़ाई से गुजरने पर इसका प्रदर्शन और पूरी तरह से ख़राब हो जाता है। इस प्रकार मुझे लगता है कि बफ़र्स पर भी यही प्रभाव लागू होगा ।Array.Copy()Buffer.BlockCopy()long
  • ~ 100 से अधिक के बफ़र आकारों के लिए, स्पष्ट लूप कॉपी जल्दी ही अन्य 2 विधियों की तुलना में बहुत धीमी हो जाती है (केवल एक विशेष अपवाद के साथ)। यह अंतर सबसे अधिक ध्यान देने योग्य है byte[], जहां स्पष्ट लूप कॉपी बड़े बफर आकारों में 7x या अधिक धीमा हो सकता है।
  • सामान्य रूप से, सभी 3 आदिम प्रकारों के लिए और सभी बफर आकारों में परीक्षण किया गया, Array.Copy()और Buffer.BlockCopy()लगभग पहचान की गई। औसतन, Array.Copy()लगता है कि लगभग 2% या उससे कम समय के लिए बहुत कम बढ़त हुई है (लेकिन 0.2% - 0.5% बेहतर विशिष्ट है), हालांकि Buffer.BlockCopy()कभी-कभी इसे हरा दिया। अज्ञात कारणों से, Buffer.BlockCopy()इसकी तुलना में उच्चतर अंतर-परीक्षण परिवर्तनशीलता है Array.Copy()। मेरे द्वारा कई मितलीकरणों की कोशिश करने और क्यों इस पर एक संचालन सिद्धांत नहीं होने के बावजूद इस प्रभाव को समाप्त नहीं किया जा सका।
  • क्योंकि Array.Copy()एक "होशियार", अधिक सामान्य, और बहुत अधिक सुरक्षित तरीका है, इसके अलावा बहुत तेज़ होने और औसत रूप से कम परिवर्तनशीलता होने के अलावा, इसे Buffer.BlockCopy()लगभग सभी सामान्य मामलों में पसंद किया जाना चाहिए । एकमात्र उपयोग मामला जहां Buffer.BlockCopy()काफी बेहतर होगा, जब स्रोत और गंतव्य सरणी मूल्य प्रकार भिन्न होते हैं (जैसा कि केन स्मिथ के उत्तर में बताया गया है)। हालांकि यह परिदृश्य आम नहीं है, Array.Copy()प्रत्यक्ष कास्टिंग की तुलना में लगातार "सुरक्षित" मूल्य प्रकार की कास्टिंग के कारण यहां बहुत खराब प्रदर्शन कर सकते हैं Buffer.BlockCopy()
  • StackOverflow के बाहर से अतिरिक्त साक्ष्य जो कि Array.Copy()एक Buffer.BlockCopy()ही प्रकार की सरणी की नकल करने की तुलना में तेज़ है , यहाँ पाया जा सकता है

एक अलग रूप में के रूप में, यह भी पता चला है कि 100 की एक सरणी लंबाई लगभग जब नेट है Array.Clear()पहले (सेटिंग करने के लिए एक सरणी के एक स्पष्ट पाश काम समाशोधन हरा शुरू होता है false, 0या, null)। यह ऊपर मेरे समान निष्कर्षों के अनुरूप है। ये अलग बेंचमार्क ऑनलाइन यहां खोजे गए थे: manski.net/2012/12/net-array-clear-vs-arrayx-0-performance
विशेष सॉस

जब आप बफर आकार कहते हैं; आप बाइट्स, या तत्व गणना में क्या मतलब है?
डामरा

मेरे उपरोक्त उत्तर में, दोनों "बफर लंबाई" और "बफर आकार" आमतौर पर तत्व गणना का उल्लेख करते हैं।
स्पेशल सॉस

मेरे पास एक उदाहरण है जहां मुझे अक्सर एक स्रोत से ऑफसेट 5 बाइट्स को पढ़ने वाले बफर में 8 बाइट्स डेटा की प्रतिलिपि बनाने की आवश्यकता होती है। मैंने पाया कि स्पष्ट लूप कॉपी काफी तेज है तो बफ़र का उपयोग करें। बैलकॉपी या एरे.कोपी। Loop Results for 1000000 iterations 17.9515ms. Buffer.BlockCopy Results for 1000000 iterations 39.8937ms. Array.Copy Results for 1000000 iterations 45.9059ms हालांकि, अगर कॉपी आकार> ~ 20 बाइट्स स्पष्ट लूप काफी धीमी है।
टॉड कनिंघम

@TodCunningham, 8 बाइट्स डेटा? आप लंबे समकक्ष मतलब है? या तो एकल तत्व (डेड फास्ट) को कास्ट करें और कॉपी करें या बस उस लूप को मैन्युअल रूप से अनियंत्रित करें।
ज्योतिषी

67

जब इसका उपयोग करने का एक और उदाहरण होता है, तो यह तब होता Buffer.BlockCopy()है जब आपको एलीमेंट्स (जैसे, शॉर्ट्स) की एक सरणी प्रदान की जाती है, और इसे बाइट्स के एक सरणी में बदलने की आवश्यकता होती है (कहते हैं, नेटवर्क पर ट्रांसमिशन के लिए)। मैं सिल्वरलाइट ऑडियोसिंक से ऑडियो के साथ काम करते समय अक्सर इस पद्धति का उपयोग करता हूं। यह एक short[]सरणी के रूप में नमूना प्रदान करता है , लेकिन आपको byte[]उस पैकेट को बनाते समय इसे एक सरणी में बदलने की आवश्यकता होती है, जिसे आप सबमिट करते हैं Socket.SendAsync()। आप उपयोग कर सकते हैं BitConverter, और सरणी के माध्यम से एक-एक करके पुनरावृति कर सकते हैं , लेकिन यह बहुत तेज है (मेरे परीक्षण में लगभग 20x) बस ऐसा करने के लिए:

Buffer.BlockCopy(shortSamples, 0, packetBytes, 0, shortSamples.Length * sizeof(short)).  

और यही चाल रिवर्स में भी काम करती है:

Buffer.BlockCopy(packetBytes, readPosition, shortSamples, 0, payloadLength);

यह लगभग उतना ही है जितना कि आप सुरक्षित C # में उस (void *)प्रकार के मेमोरी मैनेजमेंट को प्राप्त करते हैं जो C और C ++ में इतना सामान्य है।


6
यह एक अच्छा विचार है - क्या आप कभी धीरज के साथ मुद्दों में भागते हैं?
फिलिप

हाँ, मुझे लगता है कि आप अपने परिदृश्य के आधार पर उस समस्या में भाग सकते हैं। मेरे स्वयं के परिदृश्य आमतौर पर या तो (ए) हैं, मुझे बाइट सरणियों और एक ही मशीन पर लघु सरणियों के बीच आगे-पीछे स्विच करने की आवश्यकता है, या (ख) मुझे पता है कि मैं अपना डेटा उसी की मशीनों को भेज रहा हूं धीरज, और जो मैं दूरस्थ पक्ष को नियंत्रित करता हूं। लेकिन अगर आप एक प्रोटोकॉल का उपयोग कर रहे हैं जिसके लिए रिमोट मशीन को होस्ट ऑर्डर के बजाय नेटवर्क ऑर्डर में डेटा भेजे जाने की उम्मीद है, तो हाँ, यह दृष्टिकोण आपको समस्याएं देगा।
केन स्मिथ

केन ने अपने ब्लॉग पर ब्लॉककॉपी के
ड्रू नोक

4
ध्यान दें कि .Net Core 2.1 के बाद से आप इसे कॉपी किए बिना कर सकते हैं। MemoryMarshal.AsBytes<T>या MemoryMarshal.Cast<TFrom, TTo>आप किसी एक आदिम के अनुक्रम को दूसरे आदिम के अनुक्रम के रूप में व्याख्या करते हैं।
टिमो

16

मेरे परीक्षण के आधार पर, प्रदर्शन बफ़र को पसंद करने का एक कारण नहीं है। Array.Copy पर BlockCopy। मेरे परीक्षण से Array.Copy वास्तव में Buffer.BlockCopy की तुलना में तेज़ है।

var buffer = File.ReadAllBytes(...);

var length = buffer.Length;
var copy = new byte[length];

var stopwatch = new Stopwatch();

TimeSpan blockCopyTotal = TimeSpan.Zero, arrayCopyTotal = TimeSpan.Zero;

const int times = 20;

for (int i = 0; i < times; ++i)
{
    stopwatch.Start();
    Buffer.BlockCopy(buffer, 0, copy, 0, length);
    stopwatch.Stop();

    blockCopyTotal += stopwatch.Elapsed;

    stopwatch.Reset();

    stopwatch.Start();
    Array.Copy(buffer, 0, copy, 0, length);
    stopwatch.Stop();

    arrayCopyTotal += stopwatch.Elapsed;

    stopwatch.Reset();
}

Console.WriteLine("bufferLength: {0}", length);
Console.WriteLine("BlockCopy: {0}", blockCopyTotal);
Console.WriteLine("ArrayCopy: {0}", arrayCopyTotal);
Console.WriteLine("BlockCopy (average): {0}", TimeSpan.FromMilliseconds(blockCopyTotal.TotalMilliseconds / times));
Console.WriteLine("ArrayCopy (average): {0}", TimeSpan.FromMilliseconds(arrayCopyTotal.TotalMilliseconds / times));

उदाहरण आउटपुट:

bufferLength: 396011520
BlockCopy: 00:00:02.0441855
ArrayCopy: 00:00:01.8876299
BlockCopy (average): 00:00:00.1020000
ArrayCopy (average): 00:00:00.0940000

1
इस उत्तर के बारे में क्षमा करें टिप्पणी के अधिक होने के कारण, लेकिन यह एक टिप्पणी के लिए बहुत लंबा था। चूंकि सर्वसम्मति से लगता था कि बफ़र.ब्लॉककॉपी प्रदर्शन के लिए बेहतर था, मैंने सोचा कि सभी को पता होना चाहिए कि मैं परीक्षण के साथ उस सहमति की पुष्टि करने में सक्षम नहीं था।
केविन

10
मुझे लगता है कि आपके परीक्षण के तरीके में समस्या है। अधिकांश समय का अंतर जो आप नोट कर रहे हैं, आवेदन का परिणाम है, खुद को कैच करना, जेआईटी को चलाना, उस तरह की बात। इसे एक छोटे बफर के साथ आज़माएं, लेकिन कुछ हज़ार बार; और फिर पूरे परीक्षण को एक आधा दर्जन बार दोहराएं, और केवल अंतिम रन पर ध्यान दें। मेरे स्वयं के परीक्षण में बफ़र है।ब्लॉककॉपी () 640 बाइट सरणियों के लिए Array.Copy () की तुलना में शायद 5% अधिक तेज़ चल रहा है। ज्यादा तेज नहीं, लेकिन थोड़ा।
केन स्मिथ

2
मैंने एक विशिष्ट समस्या के लिए इसे मापा, मैं Array.Copy () और Buffer.BlockCopy () के बीच कोई प्रदर्शन अंतर नहीं देख सका । यदि कुछ भी हो, तो ब्लॉककॉपी ने अनिश्चितता का परिचय दिया, जिसने वास्तव में एक उदाहरण में मेरे ऐप को मार दिया
गैटोपिच

1
Array.Copy जोड़ने के लिए स्रोत की स्थिति के लिए लंबे समय का समर्थन करता है, इसलिए बड़ी बाइट सरणियों में इसे सीमा अपवाद से बाहर नहीं फेंका जाएगा।
अलक्सवेस्ट

2
परीक्षण के आधार पर मैंने अभी-अभी ( bitbucket.org/breki74/tutis/commits/… ) बनाया है, मैं कहूंगा कि जब आप बाइट सरणियों के साथ काम कर रहे हैं, तो दो तरीकों के बीच कोई व्यावहारिक प्रदर्शन अंतर नहीं है।
इगोर ब्रेजक

4

ArrayCopy BlockCopy से अधिक स्मार्ट है। यह पता लगाता है कि स्रोत और गंतव्य समान सरणी होने पर तत्वों की प्रतिलिपि कैसे बनाई जाए।

अगर हम 0,1,2,3,4 के साथ एक इंट सरणी पॉप्युलेट करते हैं और लागू होते हैं:

Array.Copy (सरणी, 0, सरणी, 1, array.Length - 1);

हम अपेक्षित रूप से 0,0,1,2,3 के साथ समाप्त होते हैं।

ब्लॉककॉपी के साथ यह कोशिश करें और हमें मिलता है: 0,0,2,3,4। यदि मैं array[0]=-1उसके बाद असाइन करता हूं , तो यह अपेक्षा के अनुसार -1,0,2,3,4 हो जाता है, लेकिन यदि सरणी की लंबाई समान है, तो 6 की तरह, हमें -1,256,2,3,4,5 मिलता है। खतरनाक सामान। एक बाइट सरणी को दूसरे में कॉपी करने के अलावा ब्लॉकचॉपी का उपयोग न करें।

एक और मामला है जहां आप केवल Array.Copy का उपयोग कर सकते हैं: यदि सरणी का आकार 2 ^ 31 से अधिक है। Array.Copy में एक longआकार पैरामीटर के साथ एक अधिभार है । ब्लॉकचोपी के पास ऐसा नहीं है।


2
ब्लॉककॉपी के साथ आपके परीक्षणों के परिणाम अप्रत्याशित नहीं हैं। ऐसा इसलिए है क्योंकि ब्लॉक कॉपी एक बार में एक बाइट के बजाय एक बार में डेटा की मात्रा को कॉपी करने की कोशिश करती है। एक 32 बिट सिस्टम पर यह एक बार में 4 बाइट्स कॉपी करता है, 64 बिट सिस्टम पर यह एक बार में 8 बाइट्स कॉपी करता है।
फ्राॅप

तो अपरिभाषित व्यवहार की उम्मीद है।
बिंकी डे

2

इस तर्क पर तौलना, अगर कोई सावधान नहीं है कि वे इस बेंचमार्क को कैसे लेखक करते हैं तो उन्हें आसानी से गुमराह किया जा सकता है। मैंने इसे स्पष्ट करने के लिए एक बहुत ही सरल परीक्षा लिखी। नीचे दिए गए मेरे परीक्षण में यदि मैं बफ़र शुरू करने के बीच अपने परीक्षणों के क्रम को स्वैप करता हूं। बैलकॉपी पहले या अर्रे.कॉपी जो पहले जाती है वह लगभग हमेशा सबसे धीमी होती है (हालांकि यह एक करीबी है)। इसका मतलब यह है कि जिन कारणों से मैं एक बार सटीक परीक्षण नहीं दूंगा, एक के बाद एक कई बार जासूसी करना चाहता हूं।

मैंने परीक्षण को बनाए रखने का सहारा लिया क्योंकि 1000000 क्रमिक युगल की एक सरणी के लिए 1000000 कोशिश करता है। हालाँकि I में पहले 900000 चक्रों की अवहेलना की गई और शेष को औसत किया गया। उस मामले में बफ़र बेहतर है।

private static void BenchmarkArrayCopies()
        {
            long[] bufferRes = new long[1000000];
            long[] arrayCopyRes = new long[1000000];
            long[] manualCopyRes = new long[1000000];

            double[] src = Enumerable.Range(0, 1000000).Select(x => (double)x).ToArray();

            for (int i = 0; i < 1000000; i++)
            {
                bufferRes[i] = ArrayCopyTests.ArrayBufferBlockCopy(src).Ticks;
            }

            for (int i = 0; i < 1000000; i++)
            {
                arrayCopyRes[i] = ArrayCopyTests.ArrayCopy(src).Ticks;
            }

            for (int i = 0; i < 1000000; i++)
            {
                manualCopyRes[i] = ArrayCopyTests.ArrayManualCopy(src).Ticks;
            }

            Console.WriteLine("Loop Copy: {0}", manualCopyRes.Average());
            Console.WriteLine("Array.Copy Copy: {0}", arrayCopyRes.Average());
            Console.WriteLine("Buffer.BlockCopy Copy: {0}", bufferRes.Average());

            //more accurate results - average last 1000

            Console.WriteLine();
            Console.WriteLine("----More accurate comparisons----");

            Console.WriteLine("Loop Copy: {0}", manualCopyRes.Where((l, i) => i > 900000).ToList().Average());
            Console.WriteLine("Array.Copy Copy: {0}", arrayCopyRes.Where((l, i) => i > 900000).ToList().Average());
            Console.WriteLine("Buffer.BlockCopy Copy: {0}", bufferRes.Where((l, i) => i > 900000).ToList().Average());
            Console.ReadLine();
        }

public class ArrayCopyTests
    {
        private const int byteSize = sizeof(double);

        public static TimeSpan ArrayBufferBlockCopy(double[] original)
        {
            Stopwatch watch = new Stopwatch();
            double[] copy = new double[original.Length];
            watch.Start();
            Buffer.BlockCopy(original, 0 * byteSize, copy, 0 * byteSize, original.Length * byteSize);
            watch.Stop();
            return watch.Elapsed;
        }

        public static TimeSpan ArrayCopy(double[] original)
        {
            Stopwatch watch = new Stopwatch();
            double[] copy = new double[original.Length];
            watch.Start();
            Array.Copy(original, 0, copy, 0, original.Length);
            watch.Stop();
            return watch.Elapsed;
        }

        public static TimeSpan ArrayManualCopy(double[] original)
        {
            Stopwatch watch = new Stopwatch();
            double[] copy = new double[original.Length];
            watch.Start();
            for (int i = 0; i < original.Length; i++)
            {
                copy[i] = original[i];
            }
            watch.Stop();
            return watch.Elapsed;
        }
    }

https://github.com/chivandikwa/Random-Benchmarks


5
मुझे आपके उत्तर में कोई समय परिणाम दिखाई नहीं देता है। कंसोल आउटपुट शामिल करें।
टूलमेकरसैट

0

बस अपने परीक्षण के मामले को जोड़ना चाहता हूं जो दिखाता है कि ब्लॉकचॉपी का Array.Copy पर कोई 'निष्पादन' लाभ नहीं है। उन्हें लगता है कि मेरी मशीन पर रिलीज़ मोड के तहत एक ही प्रदर्शन है (दोनों को 50 मिलियन पूर्णांक कॉपी करने के लिए लगभग 66ms लगते हैं)। डिबग मोड के तहत, ब्लॉककोपी बस थोड़ा तेज है।

    private static T[] CopyArray<T>(T[] a) where T:struct 
    {
        T[] res = new T[a.Length];
        int size = Marshal.SizeOf(typeof(T));
        DateTime time1 = DateTime.Now;
        Buffer.BlockCopy(a,0,res,0, size*a.Length);
        Console.WriteLine("Using Buffer blockcopy: {0}", (DateTime.Now - time1).Milliseconds);
        return res;
    }

    static void Main(string[] args)
    {
        int simulation_number = 50000000;
        int[] testarray1 = new int[simulation_number];

        int begin = 0;
        Random r = new Random();
        while (begin != simulation_number)
        {
            testarray1[begin++] = r.Next(0, 10000);
        }

        var copiedarray = CopyArray(testarray1);

        var testarray2 = new int[testarray1.Length];
        DateTime time2 = DateTime.Now;
        Array.Copy(testarray1, testarray2, testarray1.Length);
        Console.WriteLine("Using Array.Copy(): {0}", (DateTime.Now - time2).Milliseconds);
    }

3
कोई अपराध नहीं है, लेकिन आपका परीक्षा परिणाम वास्तव में उपयोगी नहीं है;) सबसे पहले "20ms तेज" आपको समग्र समय को जाने बिना कुछ भी नहीं बताता है। आपने उन दोनों परीक्षाओं को बहुत ही अलग तरीके से किया। ब्लॉककॉपी मामले में एक अतिरिक्त विधि कॉल और आपके लक्ष्य सरणी का आवंटन है जो आपके Array.Copy मामले में नहीं है। मल्टीथ्रेडिंग के उतार-चढ़ाव (संभावित कार्य स्विच, कोर स्विच) के कारण आप आसानी से अलग-अलग परिणाम प्राप्त कर सकते हैं हर बार जब आप परीक्षण निष्पादित करते हैं।
बनी 83३

@ Bunny83 टिप्पणी के लिए धन्यवाद। मैंने टाइमर स्थान को थोड़ा संशोधित किया है जिसे अब एक तुलनात्मक रूप देना चाहिए। और मुझे थोड़ी हैरानी है कि blockcopy array.copy से बिल्कुल भी तेज नहीं है।
stt106
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.