.NET简谈互操作(六:基础知识之提升平台调用性能)

简介:

互操作系列文章:

.NET简谈互操作(一:开篇介绍)

.NET简谈互操作(二:先睹为快)

.NET简谈互操作(三:基础知识之DllImport特性)

.NET简谈互操作(四:基础知识之Dispose非托管内存)

.NET简谈互操作(五:基础知识之Dynamic平台调用)

.NET简谈互操作(六:基础知识之提升平台调用性能)

.NET简谈互操作(七:数据封送之介绍)

我们继续.NET互操作学习。本篇文章我们将来学习互操作基础知识中的最后一个知识点“提升平台调用的性能”;

在于非托管函数进行互操作的过程中,由于涉及的技术因数众多,因此程序的性能会受到这些因素的影响导致性能下降,本篇文章将来介绍在平台调用过程中提升性能的一些设计和编码方面的技巧;[王清培版权所有,转载请给出署名]

一:显示的制定要调用的非托管函数名称

我们在进行平台调用的时候,如果CLR无法在非托管DLL中找到与DllImport特性指定的函数名相同的非托管函数,那么CLR会尝试采用一些规则重新进行搜索。比如我们将sumA非托管函数的CharSet申明为CharSet.Ansi,那么CLR首先会通过根函数名(sum)进行搜索,如果在指定的非托管DLL中找到了此函数,就是用它。如果不能找到,就会使用带后缀A的函数(sumA)进行搜索。其实为什么会出现这种情况,原因来自于字符编码的不同,有的函数实现是采用Ansi方式,有的采用Unicode方式,这两种编码方式的不同最终导致数据在内存的存放也不同,所以在进行非托管调用的时候,我们需要注意;

非托管代码:

 
  1. extern "C" _declspec(dllexportint _stdcall addA(int x,int y)  
  2. {  
  3.  return x+y;  

 托管代码申明1:

 
  1. [DllImport("Win32DLL.dll",EntryPoint = "add", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]  
  2. public static extern int add(int x, int y);  
  3.  

 托管代码申明2:

 
  1. [DllImport("Win32DLL.dll",EntryPoint = "addA", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall,ExactSpelling=true)]  
  2. public static extern int add(int x, int y);  
  3.  

上面两段托管代码申明有些细微的不同的,第一个托管代码是我们常见的申明方式,而第二个是我们少见的申明,两种不同的申明方式对CLR的平台调用来说是不一样的,相对而言的调用过程也有少许的不同,经测试第二种的申明能提升少许的性能;第二种的代码申明中出现了ExactSpelling=true(显式的指定要调用的非托管函数的名称),这段代码的意思是说,我们强制使用EntryPoint申明的方法入口点,不允许CLR帮我们去动态的调整函数的名称在去查找入口名称,这样能省掉了CLR的查找时间;

二:对数据封送处理进行优化

在托管代码与非托管代码之间传递参数时,无论是传入还是传出,都要经过封送拆收器的封送处理。由于封送过程可能会涉及数据类型的转换,以及在非托管内存与非托管内存之间来回复制数据,所以封送处理也是影响平台调用性能的瓶颈之一。

CLR在进行数据封送时,只有两种选择的方式:要么锁定数据、要么复制数据。在默认的情况下CLR会在封送过程中复制数据,假如我们需要将一个Unicode字符串作为Ansi传递到非托管代码中时,首先CLR会将字符串复制一份出来,然后将复制出来的字符串进行转换成Ansi,然后在将转换后的Ansi字符串的内存地址传递给非托管代码;由于复制数据操作可能很浪费时间,所以封送数据也是影响性能的瓶颈之一;

数据封送还有一种就是锁定内存的方式,意思就是说CLR可以通过直接将托管对象锁定在垃圾回收堆上,已防止托管对象在函数调用生命周期内被回收,一旦托管对象被锁定,就可以直接将指向托管对象的指针传递给非托管代码中,这样就避免了复制数据的操作,达到优化的目的;

但是不是所有的数据类型都能被锁定的,要想能被锁定,必须具备一些跟平台相关的约定,我们来看要满足那些条件的对象才能被CLR锁定;

1.必须是托管代码调用非托管代码,也就是本机代码;

2.托管数据类型必须是可直接复制到本机结构(blittable)中的数据类型,或者能够在满足某些条件下转换成本机结构数据类型;

3.传递的不是引用(ref,out)参数;

4.被调用代码和调用代码必须处于同一线程上下文或者线程单元中;

经过我们上面的总结,我们就可以发现,要想减少封送拆收器的数据复制操作,我们可以用本机结构类型进行传递,所谓本机结构类型就是在托管内存中和非托管内存中的表示形式是完全一样的。[王清培版权所有,转载请给出署名]

所以在准备开发平台调用程序时,我们尽量的考虑使用本机数据结构;如:System.Byte:无符号8位整型、System.SByte:有符号8位整型;

总结:由于这篇文章涉及到了数据封送的相关技术,很快我们结束了基础部分的学习,下面我们将进入学习互操作数据封送相关技术;


 本文转自 王清培 51CTO博客,原文链接:http://blog.51cto.com/wangqingpei557/601796,如需转载请自行联系原作者


相关文章
|
5天前
|
SQL 缓存 开发框架
分享一个 .NET EF6 应用二级缓存提高性能的方法
分享一个 .NET EF6 应用二级缓存提高性能的方法
|
1月前
|
人工智能 物联网 开发者
**.NET技术革新赋能软件开发:从.NET 5的性能飞跃、跨平台支持,到微服务、物联网、AI和游戏开发的广泛应用。
【7月更文挑战第4天】**.NET技术革新赋能软件开发:从.NET 5的性能飞跃、跨平台支持,到微服务、物联网、AI和游戏开发的广泛应用。随着云集成深化、开源社区壮大,未来将聚焦性能优化、云原生应用及新兴技术融合,培养更多开发者,驱动软件创新。**
122 1
|
2月前
|
SQL 设计模式 开发框架
.NET异步有多少种实现方式?(异步编程提高系统性能、改善用户体验)
想要知道.NET异步有多少种实现方式,首先我们要知道.NET提供的执行异步操作的三种模式,然后再去了解.NET异步实现的四种方式。
|
3月前
|
缓存 监控 算法
【专栏】.NET 开发:实现卓越性能的途径
【4月更文挑战第29天】本文探讨了.NET开发中的性能优化,强调了理解性能问题根源和使用分析工具的重要性。基础优化包括代码优化(如减少计算、避免内存泄漏)、资源管理及选择合适算法。高级策略涉及并行编程、缓存策略、预编译(AOT)和微服务架构。持续性能测试与监控是关键,包括性能测试、监控分析和建立优化反馈循环。开发者应持续学习和实践性能优化,以构建高性能应用。
48 0
|
3月前
|
数据采集 存储 监控
.NET智慧手术室管理平台源码
术前访视记录单、手术风险评估表、手术安全核查表、自费药品或耗材、麻醉知情同意书、麻醉记录单、分娩镇痛记录单、麻醉复苏单、术后镇痛记录单、术后访视记录单、压伤风险评估量表、手术清点记录单、护理记录单、输血护理记录单。
47 0
|
3月前
|
开发框架 .NET 物联网
.NET从入门到精通,零基础也能搞定的基础知识教程
.NET从入门到精通,零基础也能搞定的基础知识教程
92 0
|
3月前
深入.net平台的分层开发
深入.net平台的分层开发
|
3月前
|
Web App开发 开发框架 .NET
asp.net基于WEB层面的区域云LIS系统平台源码
asp.net基于WEB层面的区域云LIS系统平台源码
65 1
|
8月前
|
人工智能 编解码 Cloud Native
微软发布 .NET 8 开源开发平台:引入 PGO、AVX-512 支持,性能提升 20%
对企业来说特别重要的是,.NET 8 是一个长期支持 (LTS) 版本,这意味着它将获得三年的支持和补丁,而标准期限支持 (STS) 版本则是 18 个月。对于开发人员来说,特别重要的是 .NET 团队正在向期待已久的原生提前编译(NativeAOT)迈进 。
146 2
|
3月前
|
Web App开发 开发框架 .NET
asp.net基于WEB层面的云LIS系统平台源码
结合当今各检验科管理及实验室规模的不同状况,充分吸收当今IT科技的最新成就,开发出以高度产品化、功能强大、极易实施操作、并不断升级换代为主要特点的LIS系统。彻底解决检验科的信息孤岛,全面实现全院信息互通互联、高度共享,并为检验科的规范化管理提供了有力工具。
55 0