读书人

怎么高效CLONE

发布时间: 2012-10-17 10:25:47 作者: rapoo

如何高效CLONE?

C# code
public class oddsRecoder : ICloneable, IDisposable{    private bool bool_0;    private string _guid = string.Empty;    public IDictionary<string, IDictionary<string, IDictionary<string, string>>> dictionary = new Dictionary<string, IDictionary<string, IDictionary<string, string>>>();    private IDictionary<string, dic_PlayData> DataCollection = new Dictionary<string, dic_PlayData>();    public object Clone()    {        try        {            MemoryStream serializationStream = new MemoryStream();            BinaryFormatter formatter = new BinaryFormatter();            formatter.Serialize(serializationStream, this);            serializationStream.Position = 0L;            Thread.GetDomain().AssemblyResolve += new ResolveEventHandler(this.m0000ca);            object obj2 = formatter.Deserialize(serializationStream);            Thread.GetDomain().AssemblyResolve -= new ResolveEventHandler(this.m0000ca);            return obj2;        }        catch (Exception ex)        {            Console.Write(ex.Message); Log.a(ex, 1000);        }        return null;    }    public void Dispose()    {        this.m000075(true);        GC.SuppressFinalize(this);    } 

一个存放数据的类,结果发现在复制的时候相当费时,有没有更高效的方法,这里的dic_PlayData类,也有很多idictionary、string、datetime等成员,一个一个复制可能比较麻烦,大家是怎么做的呢?

[解决办法]
有个老外写的快速深度克隆,里面有讲到每种克隆的效率。还有源码你可以看下
http://blog.nuclex-games.com/mono-dotnet/fast-deep-cloning/
[解决办法]
先序列化,然后反序列化。
[解决办法]
要效率,就只能硬编码,设计类的时候就实现每个属性的克隆,序列化方式是最快的编码方式,因为通用性最强。
[解决办法]
其实是看你的执行次数,如果不是重复多次克隆,或者要大量克隆,就不需要考虑那个效率。否则你可以考虑Emit进行动态创建方法。
[解决办法]
用Emit啊,我5楼都提到过了,那个不但速度和硬编码一样(或许比硬编码更快),还有通用性,写好一个,任何类型都可用。你先自己查查资料,我这几天比较忙,最多帮你写个普通类(带继承)的Clone,累死你上面举例的类,对于特殊类型如IList、IDictionary的Clone,就不能帮忙了。
[解决办法]
探讨

你说的EMIT,是不是反射?反射效率也很低啊

[解决办法]
你对类中的一个个属性赋值,手写代码要写多少?每个类都要写一遍,内部每个属性的赋值都要写上去,要多少工作量你想过吗?当然这样也是执行效率最高的,但是通过EMIT就可以实现通用方法,让机器代替人工去硬编码。
[解决办法]
有一个开源FastSerializer c#服务器程序大都是用他。不过也是来自国外。
这个国际用的比较多。据国外的一个测试效率是最高的。
但不知道是不是和二楼给出是不是同一个。
[解决办法]
探讨

有一个开源FastSerializer c#服务器程序大都是用他。不过也是来自国外。
这个国际用的比较多。据国外的一个测试效率是最高的。
但不知道是不是和二楼给出是不是同一个。

[解决办法]
给你写了一段简单的Emit代码,只支持简单类型的类(属性都为基础数据类型),真的是很忙,没时间分析负责类型,仅为了证明这个方法是最快的,手写都没这速度。
核心代码:
C# code
        static List<FieldInfo> GetSettableFields(Type t)        {            return t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToList();        }        //暂时只能支持简单类的克隆,也就是类的内部只有基础类型。        static Func<object, object> CreateCloneMethod(Type type)        {            var fields = GetSettableFields(type);            var dm = new DynamicMethod(string.Format("Clone{0}", Guid.NewGuid()), typeof(object), new[] { typeof(object) }, true);            var il = dm.GetILGenerator();            il.DeclareLocal(type);            il.DeclareLocal(type);            il.Emit(OpCodes.Newobj, type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null));            il.Emit(OpCodes.Dup);            il.Emit(OpCodes.Stloc_1);            il.Emit(OpCodes.Ldarg_0);            il.Emit(OpCodes.Castclass, type);            il.Emit(OpCodes.Stloc_0);            foreach (var field in fields)            {                il.Emit(OpCodes.Ldloc_1);                il.Emit(OpCodes.Ldloc_0);                il.Emit(OpCodes.Ldfld, field);                il.Emit(OpCodes.Stfld, field);            }            il.Emit(OpCodes.Ret);            return (Func<object, object>)dm.CreateDelegate(typeof(Func<object, object>));        } 


[解决办法]
效率比较:

C# code
Func<object, object> clone = CreateCloneMethod(typeof(DT_USER));DT_USER u1 = new DT_USER() { USER_NO = 1, USER_LNAME = "001" };DT_USER u2 = null;Stopwatch sw = new Stopwatch();sw.Start();for (int i = 0; i < 100000; i++){    u2 = u1.Clone();}sw.Stop();Console.WriteLine("手写代码克隆执行10万次所用时间:" + sw.ElapsedMilliseconds + "毫秒");sw.Restart();for (int i = 0; i < 100000; i++){    u2 = clone(u1) as DT_USER;}sw.Stop();Console.WriteLine("Emit执行10万次所用时间:" + sw.ElapsedMilliseconds + "毫秒");sw.Restart();for (int i = 0; i < 100000; i++){    MemoryStream serializationStream = new MemoryStream();    BinaryFormatter formatter = new BinaryFormatter();    formatter.Serialize(serializationStream, u1);    serializationStream.Position = 0;    u2 = formatter.Deserialize(serializationStream) as DT_USER;    serializationStream.Close();}sw.Stop();Console.WriteLine("序列化方式执行10万次所用时间:" + sw.ElapsedMilliseconds + "毫秒");
[解决办法]
要是跟我一样对Emit不熟的话还是硬编码执行速度最快了。
[解决办法]
探讨
手写代码克隆执行10万次所用时间:28毫秒
Emit执行10万次所用时间:18毫秒
序列化方式执行10万次所用时间:6185毫秒

[解决办法]
探讨
TO:qldsrx
对于你的这个测试,我不是很理解,因为硬编码在执行一次就转化为MSIL,跟EMIT一样了,双方应该是一样的吧,我查了一下,貌似整体EMIT的性能接近硬编码,但要差,可能只有在赋值方面,才可以超过,但也是差不多了,他并不能大幅提高性能。
我的这个类的CLOnE,包括泛型字典,有EMIT有解吗?本想结贴,还没有跟你聊够呢,哈哈~~

[解决办法]
探讨
功能不(基本)完善的,可以不考虑。

然后考虑价值(到底值几毛钱)和开发成本,可见序列化虽然慢一些,但是达到了可以忽略的程度。

读书人网 >C#

热点推荐