登录
/
注册
首页
论坛
其它
首页
科技
业界
安全
程序
社区
BBS
广播
Follow
园子
关于
博客
发1篇日志+1圆
记录
发1条记录+2圆币
发帖说明
登录
/
注册
账号
自动登录
找回密码
密码
登录
立即注册
搜索
搜索
关闭
CSDN热搜
程序园
精品问答
技术交流
资源下载
本版
帖子
用户
软件
问答
教程
代码
VIP申请
网盘
联系我们
道具
勋章
任务
设置
我的收藏
退出
腾讯QQ
微信登录
返回列表
首页
›
业界区
›
业界
›
.NET框架:为什么我们要尽量使用框架内建的功能,而不是 ...
.NET框架:为什么我们要尽量使用框架内建的功能,而不是重新发明
[ 复制链接 ]
荏牌
2025-5-29 15:33:39
有很多人经常会持有这样的疑问:为什么 .NET 框架要把一些很简单的功能也封装起来?
而有些人所坚持的“有现成的就用现成的”的习惯在那些“明明只是很简单的功能却被封装了起来”的情况下也显得很可笑。
那么,实际上到底有没有必要用那些本来就很简单的封装?这些简单的封装到底具有什么样的意义呢?
其实大部分这样的简单的封装都是针对“跨平台使用”而设计的。
有些人可能会说:.NET 框架有什么跨平台可言?
其实 .NET 框架虽然现在只提供 Windows 上的版本,但其它平台上的 CLI 实现,如 Mono、DotGNU 等等也都有赖于 .NET 框架和 CLI 的预见性方能成为现实;而可以在多种环境中使用的 RIA 平台 Silverlight 也是将这种思想发挥到了极致。
举个例子来说,.NET 框架中 IPAddress 类型具有 NetworkToHostOrder 和 HostToNetworkOrder 方法,如果你使用 Reflector 来查看反编译后的代码,你会发现 NetworkToHostOrder 只是调用了 HostToNetworkOrder,而 HostToNetworkOrder 的原理也只不过是一些简单的位移运算而已。
有的人看到这里可能会想:包了两层方法性能多差啊,用到它的地方自己写位移运算不是也可以么?
不要这样做。
实际上,CLR 的 JIT 编译功能会把简单的方法进行内联编译,所以像是 NetworkToHostOrder 这样的方法在进行 JIT 编译之后结果和直接使用位移运算并没有区别,而在这里偏执地直接使用位移运算,不仅性能没有实质上的提升,还会导致代码难以维护;而且这样的代码如果到了使用 Big-Endian 字节序的计算机上,就不能用了!
当然了,如果你善于使用预编译指令之类的工具,这种问题也自然难不倒你。
与此相似的,还有:
有些具有 Visual Basic 5/6 编程经验的人在使用 Win32API 的时候会习惯使用 Long 或者 Int32 来当作各种 Handle 的等价类型,然而这样做是错的!
如果你去查看 SDK 中关于 HANDLE 的定义,你会发现:
typedef PVOID HANDLE;
复制代码
也就是说,实际上在 64 位程序里,Handle 和指针一样,是 64 位的——虽然绝大部分情况下这 64 位的 Handle 只有低 32 位有效,但是数据类型本身需要的 64 位空间不能忽视。
所以实际上在需要用到任何类型的 Handle 的场所,都应该使用 IntPtr,而非 Visual Basic 中的 Long 或者 CLR 中的 Int32,这样才能保证代码在 IA-64、x86-64 硬件平台上正常运行。
而最为有用,又最为复杂,以致于很多人不愿意去了解的,则是关于“低锁定技术”的各种封装。
例如,ReaderWriterLock(Slim)、Lazy、ConcurrentDictionary等等。
由于这些封装的内部实现实在是很复杂,不管是从篇幅上考虑还是从笔者我的能力上去考虑,想详细、深入地去解释实在是不现实,所以这里只能介绍一下大致上的原理了。
低锁定技术是一种由来已久的设计方式,有兴趣的人可以在网络上自行搜索相关的资料。
低锁定技术的大致思路就是:对于没有初始化的值,在第一次读取的时候需要锁定并将之初始化;一经初始化之后,进行读取时不需要任何锁定操作。
不过尽管低锁定看上去是个很聪明的做法,可实际实现起来却要考虑很多问题,因此也有很多文章警告过,不要尝试实现低锁定,因为实际上是会产生意外的。
实际上 CPU 可能会按照一定的模式来优化内存操作,改变某些读、写操作的顺序;又或者是因为读取了已经缓存的数据而导致了判断失误,致使同一时间尝试进行访问的其它线程读取到了错误的数据,结果采用低锁定技术的程序却发生了异常。
关于这个问题,想要了解细节的同学可以参考这些文章:http://msdn.microsoft.com/en-us/magazine/cc163715.aspx、http://www.ibm.com/developerworks/cn/java/j-dcl.html、http://msdn.microsoft.com/en-us/library/ff650316.aspx、http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
。
尽管这样的问题也可以通过精密的设计而解决,但如果你使用过 C/C++ 并且知道 MemoryBarrier 的概念,你也可以发现下面这些东西:
#ifdef _AMD64_
#define MemoryBarrier __faststorefence
#endif
#ifdef _IA64_
#define MemoryBarrier __mf
#endif
// x86
FORCEINLINE
VOID
MemoryBarrier (
VOID
)
{
LONG Barrier;
__asm {
xchg Barrier, eax
}
}
复制代码
这也说明在不同的平台上,由内存模型或其它技术细节上的差异所导致的问题,具体的解决办法也是各不相同的。
而对于我们一般的应用程序开发人员来说,要想全面掌握这些解决办法,并且在每个必要的场合准确无误地采取合适的办法也是相当困难的。
其实这样繁琐的问题本来就不应该让一般应用程序开发人员去面对,而是应该让 .NET 框架之类的靠近底层的设施去解决。
所以对于使用 C/C++ 的开发人员来说,当他们用到 MemoryBarrier 的时候,并不需要真的根据目标平台而写入实际的操作代码,只需要插入相应的 MACRO 就可以了。
而实际上,.NET 框架也把这一部分隐藏了起来,在 MSDN 博客上有博文解释了在 CLR 中实现了一种正确的内存操作模型(链接:http://blogs.msdn.com/b/cbrumme/archive/2003/05/17/51445.aspx),而且无论哪种平台上的 .NET 框架(或者其等价物)都会保证它们的行为一致;
同时 .NET 框架中提供的诸如 Lazy、ConcurrentDictionary 等类型,也有助于避免由于对内存模型不了解(比方说,你知道使用 lock 时是不是应该同时使用 MemoryBarrier 或者 Volatile 吗?又或者,你知道应该在什么时候使用、什么时候不需要使用吗?),或者一时间的逻辑误区而写出了存在潜在问题、导致程序不稳定的代码的情形发生。
总地来说,除非是对底层的技术细节具有相当高的程度的了解,并且具有极强的信心可以解决任何问题……否则还是“有现成的就用现成的”比较好,因为这样做的话 .NET 框架会为你解决好那些恼人的跨平台兼容性问题。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复
使用道具
举报
提升卡
置顶卡
沉默卡
喧嚣卡
变色卡
千斤顶
照妖镜
相关推荐
那些年搞不懂的高深术语——依赖倒置•控制反转•依赖注入•面向接口编程
如何优雅的使用RabbitMQ
分布式锁1 Java常用技术方案
浅谈我对DDD领域驱动设计的理解
游戏编程十年总结(下)
【前端性能】高性能滚动 scroll 及页面渲染优化
验证码对抗之路及现有验证机制介绍
中文写程序,何陋之有?
从零开始入门 K8s | 手把手带你理解 etcd
NHibernate之旅(2):第一个NHibernate程序
公司的中场
FFmpeg开发笔记(六十二)Windows给FFmpeg集成H.266编码器vvenc
Android 系统缺陷不完全点评
.net环境下跨进程、高频率读写数据
谈谈如何从本质上理解sql语句, 存储过程,ORM之间的联系和取舍。
[一步一步MVC]第一回:使用ActionSelector控制Action的选择
模板模式
第二个iPhone应用程序:“Say Hello”
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
立即注册
回复
本版积分规则
回帖并转播
回帖后跳转到最后一页
浏览过的版块
代码
科技
签约作者
程序园优秀签约作者
发帖
荏牌
2025-5-29 15:33:39
关注
0
粉丝关注
12
主题发布
板块介绍填写区域,请于后台编辑
财富榜{圆}
敖可
9986
里豳朝
9994
背竽
9994
4
猷咎
9992
5
凶契帽
9992
6
终秀敏
9990
7
森萌黠
9990
8
裴涛
9990
9
贼瘁
9990
10
鞍汉
9990
查看更多