Q. मैं इस उत्तर को क्यों चुनूंगा?
- यदि आप सबसे तेज गति चाहते हैं, तो यह उत्तर चुनें। .NET सक्षम है।
- यदि आप क्लोनिंग का एक बहुत ही आसान तरीका चाहते हैं, तो इस उत्तर को अनदेखा करें।
दूसरे शब्दों में, एक और उत्तर के साथ जाएं जब तक कि आपके पास एक प्रदर्शन अड़चन न हो जिसे फिक्सिंग की आवश्यकता हो, और आप इसे एक प्रोफाइलर के साथ साबित कर सकते हैं ।
अन्य तरीकों की तुलना में 10 गुना तेज
गहरी क्लोन करने की निम्न विधि है:
- किसी भी चीज़ की तुलना में तेज़ी से 10x, जिसमें क्रमांकन / डीसेरिएलाइज़ेशन शामिल है;
- सैद्धांतिक अधिकतम गति .NET के करीब सुंदर रंगमंच सक्षम है।
और विधि ...
अंतिम गति के लिए, आप नेस्टेड सदस्यवार का उपयोग कर सकते हैं एक गहरी प्रतिलिपि बनाने के लिए । मान संरचना की प्रतिलिपि बनाने के रूप में इसकी लगभग समान गति है, और (ए) प्रतिबिंब या (बी) क्रमांकन की तुलना में बहुत तेज है (जैसा कि इस पृष्ठ पर अन्य उत्तरों में वर्णित है)।
ध्यान दें कि यदि आप एक गहरी प्रतिलिपि के लिए नेस्टेड मेंबरवाइज क्लोन का उपयोग करते हैं , तो आपको कक्षा में प्रत्येक नेस्टेड स्तर के लिए मैन्युअल रूप से एक ShallowCopy को लागू करना होगा, और एक DeepCopy जो एक संपूर्ण क्लोन बनाने के लिए सभी ShallowCopy विधियों को कॉल करता है। यह सरल है: कुल में केवल कुछ पंक्तियाँ, नीचे डेमो कोड देखें।
यहां 100,000 क्लोन के लिए सापेक्ष प्रदर्शन अंतर दिखाते हुए कोड का आउटपुट है:
- नेस्टेड स्ट्रक्चर्स पर नेस्टेड मेम्बरवाइज के लिए 1.08 सेकंड
- नेस्टेड सदस्य के लिए 4.77 सेकंड नेस्टेड कक्षाओं पर क्लिक करें
- 39.93 सेकंड के लिए सीरियलाइज़ेशन / डिसेरिएलाइज़ेशन
नेस्टेड मेम्बरवाइज़लोन का उपयोग करके किसी संरचना की नकल करने में लगभग उतना ही तेज है, और एक संरचना की नकल करना सैद्धांतिक अधिकतम गति के करीब सुंदर है। .NET सक्षम है।
Demo 1 of shallow and deep copy, using classes and MemberwiseClone:
Create Bob
Bob.Age=30, Bob.Purchase.Description=Lamborghini
Clone Bob >> BobsSon
Adjust BobsSon details
BobsSon.Age=2, BobsSon.Purchase.Description=Toy car
Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:
Bob.Age=30, Bob.Purchase.Description=Lamborghini
Elapsed time: 00:00:04.7795670,30000000
Demo 2 of shallow and deep copy, using structs and value copying:
Create Bob
Bob.Age=30, Bob.Purchase.Description=Lamborghini
Clone Bob >> BobsSon
Adjust BobsSon details:
BobsSon.Age=2, BobsSon.Purchase.Description=Toy car
Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:
Bob.Age=30, Bob.Purchase.Description=Lamborghini
Elapsed time: 00:00:01.0875454,30000000
Demo 3 of deep copy, using class and serialize/deserialize:
Elapsed time: 00:00:39.9339425,30000000
यह समझने के लिए कि मेंबरकॉपी का उपयोग करके एक गहरी कॉपी कैसे की जाती है, यहां डेमो प्रोजेक्ट है जिसका उपयोग ऊपर दिए गए समय को उत्पन्न करने के लिए किया गया था:
// Nested MemberwiseClone example.
// Added to demo how to deep copy a reference class.
[Serializable] // Not required if using MemberwiseClone, only used for speed comparison using serialization.
public class Person
{
public Person(int age, string description)
{
this.Age = age;
this.Purchase.Description = description;
}
[Serializable] // Not required if using MemberwiseClone
public class PurchaseType
{
public string Description;
public PurchaseType ShallowCopy()
{
return (PurchaseType)this.MemberwiseClone();
}
}
public PurchaseType Purchase = new PurchaseType();
public int Age;
// Add this if using nested MemberwiseClone.
// This is a class, which is a reference type, so cloning is more difficult.
public Person ShallowCopy()
{
return (Person)this.MemberwiseClone();
}
// Add this if using nested MemberwiseClone.
// This is a class, which is a reference type, so cloning is more difficult.
public Person DeepCopy()
{
// Clone the root ...
Person other = (Person) this.MemberwiseClone();
// ... then clone the nested class.
other.Purchase = this.Purchase.ShallowCopy();
return other;
}
}
// Added to demo how to copy a value struct (this is easy - a deep copy happens by default)
public struct PersonStruct
{
public PersonStruct(int age, string description)
{
this.Age = age;
this.Purchase.Description = description;
}
public struct PurchaseType
{
public string Description;
}
public PurchaseType Purchase;
public int Age;
// This is a struct, which is a value type, so everything is a clone by default.
public PersonStruct ShallowCopy()
{
return (PersonStruct)this;
}
// This is a struct, which is a value type, so everything is a clone by default.
public PersonStruct DeepCopy()
{
return (PersonStruct)this;
}
}
// Added only for a speed comparison.
public class MyDeepCopy
{
public static T DeepCopy<T>(T obj)
{
object result = null;
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
result = (T)formatter.Deserialize(ms);
ms.Close();
}
return (T)result;
}
}
फिर, मुख्य से डेमो कॉल करें:
void MyMain(string[] args)
{
{
Console.Write("Demo 1 of shallow and deep copy, using classes and MemberwiseCopy:\n");
var Bob = new Person(30, "Lamborghini");
Console.Write(" Create Bob\n");
Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
Console.Write(" Clone Bob >> BobsSon\n");
var BobsSon = Bob.DeepCopy();
Console.Write(" Adjust BobsSon details\n");
BobsSon.Age = 2;
BobsSon.Purchase.Description = "Toy car";
Console.Write(" BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);
Console.Write(" Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");
Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
Debug.Assert(Bob.Age == 30);
Debug.Assert(Bob.Purchase.Description == "Lamborghini");
var sw = new Stopwatch();
sw.Start();
int total = 0;
for (int i = 0; i < 100000; i++)
{
var n = Bob.DeepCopy();
total += n.Age;
}
Console.Write(" Elapsed time: {0},{1}\n\n", sw.Elapsed, total);
}
{
Console.Write("Demo 2 of shallow and deep copy, using structs:\n");
var Bob = new PersonStruct(30, "Lamborghini");
Console.Write(" Create Bob\n");
Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
Console.Write(" Clone Bob >> BobsSon\n");
var BobsSon = Bob.DeepCopy();
Console.Write(" Adjust BobsSon details:\n");
BobsSon.Age = 2;
BobsSon.Purchase.Description = "Toy car";
Console.Write(" BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);
Console.Write(" Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");
Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
Debug.Assert(Bob.Age == 30);
Debug.Assert(Bob.Purchase.Description == "Lamborghini");
var sw = new Stopwatch();
sw.Start();
int total = 0;
for (int i = 0; i < 100000; i++)
{
var n = Bob.DeepCopy();
total += n.Age;
}
Console.Write(" Elapsed time: {0},{1}\n\n", sw.Elapsed, total);
}
{
Console.Write("Demo 3 of deep copy, using class and serialize/deserialize:\n");
int total = 0;
var sw = new Stopwatch();
sw.Start();
var Bob = new Person(30, "Lamborghini");
for (int i = 0; i < 100000; i++)
{
var BobsSon = MyDeepCopy.DeepCopy<Person>(Bob);
total += BobsSon.Age;
}
Console.Write(" Elapsed time: {0},{1}\n", sw.Elapsed, total);
}
Console.ReadKey();
}
फिर से, ध्यान दें कि यदि आप एक गहरी प्रतिलिपि के लिए नेस्टेड मेंबरवाइज क्लोन का उपयोग करते हैं , तो आपको कक्षा में प्रत्येक नेस्टेड स्तर के लिए मैन्युअल रूप से एक ShallowCopy को लागू करना होगा, और एक DeepCopy जो एक संपूर्ण क्लोन बनाने के लिए सभी ShallowCopy विधियों को कॉल करता है। यह सरल है: कुल में केवल कुछ पंक्तियाँ, ऊपर डेमो कोड देखें।
मान प्रकार बनाम संदर्भ प्रकार
ध्यान दें कि जब किसी ऑब्जेक्ट को क्लोन करने की बात आती है, तो " संरचना " और " क्लास " के बीच एक बड़ा अंतर होता है :
- यदि आपके पास " संरचना " है, तो यह एक मूल्य प्रकार है ताकि आप इसे कॉपी कर सकें, और सामग्री को क्लोन किया जाएगा (लेकिन यह केवल एक उथले क्लोन बना देगा जब तक कि आप इस पोस्ट में तकनीकों का उपयोग न करें)।
- यदि आपके पास " क्लास " है, तो यह एक संदर्भ प्रकार है , इसलिए यदि आप इसे कॉपी करते हैं, तो आप जो कुछ भी कर रहे हैं वह सूचक को कॉपी कर रहा है। एक सच्चे क्लोन बनाने के लिए, आपको अधिक रचनात्मक होना होगा, और मूल्य प्रकार और संदर्भ प्रकारों के बीच अंतर का उपयोग करना होगा जो स्मृति में मूल वस्तु की एक और प्रतिलिपि बनाता है।
मूल्य प्रकार और संदर्भ प्रकारों के बीच अंतर देखें ।
डिबगिंग में सहायता करने के लिए चेकसम
- वस्तुओं को गलत तरीके से क्लोन करने से बहुत मुश्किल से पिन-डाउन कीड़े हो सकते हैं। उत्पादन कोड में, मैं एक चेकसम लागू करने के लिए दोहराता हूं कि ऑब्जेक्ट को ठीक से क्लोन किया गया है, और इसे किसी अन्य संदर्भ से दूषित नहीं किया गया है। इस चेकसम को रिलीज़ मोड में बंद किया जा सकता है।
- मुझे यह तरीका काफी उपयोगी लगता है: अक्सर, आप केवल ऑब्जेक्ट के कुछ हिस्सों को क्लोन करना चाहते हैं, न कि पूरी चीज को।
कई अन्य थ्रेड्स से कई थ्रेड्स को डिकूप करने के लिए वास्तव में उपयोगी है
इस कोड के लिए एक उत्कृष्ट उपयोग मामला निर्माता / उपभोक्ता पैटर्न को लागू करने के लिए एक नेस्टेड वर्ग या संरचना के एक पंक्ति में क्लोन खिला रहा है।
- हमारे पास एक (या अधिक) धागे हो सकते हैं जो एक वर्ग को संशोधित करते हैं जो उनके पास होते हैं, फिर इस वर्ग की पूरी प्रतिलिपि को एक में धकेलते हैं
ConcurrentQueue
।
- हमारे पास तब एक (या अधिक) धागे होते हैं जो इन वर्गों की प्रतियों को बाहर निकालते हैं और उनसे निपटते हैं।
यह अभ्यास में बहुत अच्छी तरह से काम करता है, और हमें एक या एक से अधिक थ्रेड्स (उपभोक्ताओं) से कई थ्रेड्स (उत्पादकों) को हटाने की अनुमति देता है।
और यह विधि बहुत तेजी से अंधाधुंध है: यदि हम नेस्टेड संरचनाओं का उपयोग करते हैं, तो यह नेस्टेड क्लासेसिंग / डिसेरिएलाइजिंग नेस्टेड क्लासेस की तुलना में 35 गुना तेज है, और हमें मशीन पर उपलब्ध सभी थ्रेड्स का लाभ उठाने की अनुमति देता है।
अपडेट करें
जाहिर है, ExpressMapper उपवास के रूप में हाथ कोडिंग की तुलना में तेजी से, अगर नहीं है। मुझे यह देखना होगा कि वे एक प्रोफाइलर के साथ तुलना कैसे करते हैं।