志在指尖
用双手敲打未来

类与结构体性能对比测试

1.背景
接上篇文章深化浅出C#构造体——封装以太网心跳包的构造为例,运用构造体性能不佳,而且也阐明了缘由。本篇文章细致描绘了以类来封装网络心跳包的优缺陷,结果大大提升理解析性能。
2.用类来封装以太网心跳包的优缺陷
2.1.优点
能够在类里直接newbyte[],即直接实例字节数组,然后写初始化办法或者结构函数中直接对传进来的缓存停止拷贝赋值;
无需装箱拆箱;
类属于援用类型,无需像构造体停止值拷贝,底层直接就是智能指针;
智能指针指向同一片内存,省内存空间;
能够在类里写很多便当的办法,这也就是面向对象,面向范畴的基石,便当以后扩展;
2.2.缺陷
存在堆里,读取性能会比栈稍差(如今PC端的计算速度很快,根本可疏忽不计);
固然类也属于GC的托管资源,但是GC什么时分停止自动回收不可控制,需求完成IDisposable接口,用完该类,手动对该类停止释放动作;
运用类的实践性能怎样,我们用测试数听说话,后面会放上与构造体测试的性能比照数据。C#
3.网络心跳包封装类
这里全部都命名成了字节数组,包括publicbyte[]type=newbyte[1];由于假如是bytetype类型,我不晓得如何去释放这一值类型,怕到时分惹起内存泄露等问题。然后在结构函数里面将缓存buf拷贝到了类的各个属性中,就是这么简单。
publicclassTcpHeartPacketClass:BaseDisposable
{
privatebool_disposed;//表示能否曾经被回收
publicTcpHeartPacketClass(byte[]buf)
{
Buffer.BlockCopy(buf,0,head,0,4);
type[0]=buf[4];
Buffer.BlockCopy(buf,4,length,0,2);
Buffer.BlockCopy(buf,6,Mac,0,6);
Buffer.BlockCopy(buf,12,data,0,104);
Buffer.BlockCopy(buf,116,tail,0,4);
}
protectedoverridevoidDispose(booldisposing)
{
if(!_disposed)//假如还没有被回收
{
if(disposing)//假如需求回收一些托管资源
{
//TODO:回收托管资源,调用IDisposable的Dispose()办法就能够
}
//TODO:回收非托管资源,把之设置为null,等候CLR调用析构函数的时分回收
head=null;
type=null;
length=null;
Mac=null;
data=null;
tail=null;
_disposed=true;
}
base.Dispose(disposing);//再调用父类的渣滓回收逻辑
}
publicbyte[]head=newbyte[4];
publicbyte[]type=newbyte[1];
publicbyte[]length=newbyte[2];
publicbyte[]Mac=newbyte[6];
publicbyte[]data=newbyte[104];//数据体
publicbyte[]tail=newbyte[4];
}
4.完成IDisposable接口
用完类之后,为了主动去释放类,我封装了一个释放基类BaseDisposable。详见代码注释,有不明白的中央能够在评论区发问,我会细致作答。
publicclassBaseDisposable:IDisposable
{
~BaseDisposable()
{
//渣滓回收器将调用该办法,因而参数需求为false。
Dispose(false);
}
///
///能否曾经调用了Dispose(booldisposing)办法。
///应该定义成private的,这样能够使基类和子类互不影响。
///
privatebooldisposed=false;
///
///一切回收工作都由该办法完成。
///子类应重写(override)该办法。
///
///
protectedvirtualvoidDispose(booldisposing)
{
//防止反复调用Dispose。
if(!disposed)return;
//顺应多线程环境,防止产生线程错误。
lock(this)
{
if(disposing)
{
//————————————————
//在此处写释放托管资源的代码
//(1)有Dispose()办法的,调用其Dispose()办法。
//(2)没有Dispose()办法的,将其设为null。
//例如:
//xxDataTable.Dispose();
//xxDataAdapter.Dispose();
//xxString=null;
//————————————————
}
//————————————————
//在此处写释放非托管资源
//例如:
//文件句柄等
//————————————————
disposed=true;
}
}
///
///该办法由程序调用,在调用该办法之后对象将被终结。
///该办法定义在IDisposable接口中。
///
publicvoidDispose()
{
//由于是由程序调用该办法的,因而参数为true。
Dispose(true);
//由于我们不希望渣滓回收器再次终结对象,因而需求从终结列表中去除该对象。
GC.SuppressFinalize(this);
}
///
///调用Dispose()办法,回收资源。
///
publicvoidClose()
{
Dispose();
}
}
5.应用层调用
DateTimepacketClassStart=DateTime.Now;
TcpHeartPacketClasstcpHeartPacketClass=neTcpHeartPacketClass(ReceviveBuff);
DateTimepacketClassEnd=DateTime.Now;
TimeSpantoClassTs=packetClassEnd.Subtra(packetClassStart);
try
{
tcpHeartPacketClass.head[0]=0x11;
LoggerHelper.Info(“类中的包头:”+BitConverteToString(tcpHeartPacketClass.head));
Console.WriteLine(“类中的包头:{0}”,BitConverteToString(tcpHeartPacketClass.head));
LoggerHelper.Info(“类中的包类型:”tcpHeartPacketClass.type.ToString());
Console.WriteLine(“类中的包类型:{0}”tcpHeartPacketClass.type.ToString());
LoggerHelper.Info(“类中的包长度:”+BitConverteToString(tcpHeartPacketClass.length));
Console.WriteLine(“类中的包长度:{0}”,BitConverteToString(tcpHeartPacketClass.length));
LoggerHelper.Info(“类中的MAC地址:”+BitConverteToString(tcpHeartPacketClass.Mac));
Console.WriteLine(“类中的MAC地址:{0}”,BitConverteToString(tcpHeartPacketClass.Mac));
LoggerHelper.Info(“类中的注册包内容:”+BitConverteToString(tcpHeartPacketClass.data));
Console.WriteLine(“类中的注册包内容:{0}”BitConverter.ToString(tcpHeartPacketClass.data));
LoggerHelper.Info(“类中的包尾:”+BitConverteToString(tcpHeartPacketClass.tail));
Console.WriteLine(“类中的包尾:{0}”,BitConverteToString(tcpHeartPacketClass.tail));
Console.WriteLine(“字节数组类中分割总共破费{0}ms\n”toClassTs.TotalMilliseconds);
}
finally
{
IDisposabledisposable=tcpHeartPacketClassasIDisposable;
if(disposable!=null)
disposable.Dispose();
}
6.Dispose()办法生效的测试
在ty…finally块执行完Dispose()办法之后,再去给类的某个属性赋值,我们看能否报错,假如报错赋值给空对象则证明释放胜利。
finally
{
IDisposabledisposable=tcpHeartPacketClassIDisposable;
if(disposable!=null)
disposable.Dispose();
}
tcpHeartPacketClass.head[0]=0x12;
如下报错,翻译过来意义就是对象援用没有对应的实例,也就是被我们给释放掉了。
7.测试性能比照
经过上图能够看到,上面的类解析的是微秒级别的,而文章深化浅出C#构造体——封装以太网心跳包的构造为例解析的是几十微秒级别的,差了差不多5到10倍的性能。
由此可见,在这种应用场景下,运用类来封装网络心跳包比构造体封装更合理。
8.综上,在C#里,构造体主要作用有如下两点:
数据长度很短,结构16字节以下的新类型,而且构造体内的子类型必需是值类型,不然没意义,其目的是为了顺应栈上的高效读取;
为了兼容一些来自C跟C++的库;
避开以上两点,我以为在C#新开发的应用程序中,能够完整的用类来取代构造体(仅代表个人观念)。

未经允许不得转载:IT技术网站 » 类与结构体性能对比测试
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

志在指尖 用双手敲打未来

登录/注册IT技术大全

热门IT技术

C#基础入门   SQL server数据库   系统SEO学习教程   WordPress小技巧   WordPress插件   脚本与源码下载