C#和C++可以交互使用高性能代码吗?
我们有执行高性能数据处理的传统C++代码(例如,从硬件设备馈入的大量数据以时间敏感的方式处理,以便显示,转换并传输到辅助存储器)。C#和C++可以交互使用高性能代码吗?
我们对新的GUI和新实用工具(现有的GUI是C++ MFC和Qt)的C#/ .NET感兴趣。当然,对于现有的系统,我们没有.NET虚拟机的“语言翻译”问题(现有代码都是C++)。
经过大量研究和许多书籍,我不确定这可以有效地完成。可能的方法(我错过任何?):
- 重写一切都在.NET(不能 发生 - 太多的代码,裸机设备访问,时间敏感的重算法处理)
- 薄对于托管的托管 C++/CLI
- 厚适配器层适配层 C++/CLI
- 不要使用.NET(经理感到极大的悲伤 )
我们对(2)“精简适配器层”的关注是,如果GUI可以(重新)使用“业务”层中的逻辑(许多属性由算法派生),那将会很好,所以如果我们不公开/包装C++类,很多GUI逻辑将仅复制业务层中现有的C++逻辑。我们对(3)“粗适配器层”的担忧是,用C#类来包装每个C++类似乎非常繁琐(昂贵),并且一些书籍表明跨该边界的装箱/拆箱访问似乎暗示了这一点方法是不可行的/令人望而生畏的(除了微不足道的设计之外,它的表现令人望而却步)。
你如何在C++中实现的深富阶级结构的顶部接口新的C#/。NET(GUI)?
C++/CLI是完美的。托管/非托管翻译没有性能问题,因为C++/CLI使用.NET运行时引擎自身使用的相同的优化调用技术来实现字符串连接等高性能方法。
当您在.NET和相同数据结构的本机版本之间来回复制数据时,会出现性能问题,但是您也会遇到同样的问题。使用一个使用BSTR的库,并使用std::string
,缓慢的操作同样明显(与P/Invoke不同,后者试图使这些翻译变得透明,最终隐藏了过程中的性能问题)。
还有一些技巧可以用来克服这一点。例如,不是将std::vector
复制到System::Collections::Generic::List
中,而是实施从std::vector
直接读取的IEnumerator
。
当然,如果数据只是直接传递回另一个C++函数,那么根本没有理由将其转换为托管类型。再一次,C++/CLI使保存格式变得简单,P/Invoke试图转换背后的所有内容。
总之,“瘦”的C++/CLI包装层是最好的选择。
您对约束有正确的想法。跨越边界是昂贵的,你不想为细粒度的操作做到这一点。如何细粒度? 当然,这取决于。
在理想的情况下,您的C++代码被分层到一个理性的对象模型中,通过这个模型你可以为一个更大粒度的操作放置一个COM层(或类似的)。举一个例子,你不希望公开一个包含5个属性的对象,并且每个对象都有一个setter/getter对,你会希望公开一个SetProperties()方法,该方法接受要设置的所有属性的映射。这绝不是唯一需要注意的情况;这只是一个如何将自己倾向于更大粒度操作的例子。
关于COM - 这很好,但当然不是必需的。使用COM强制执行一项规定,因为您需要正式定义COM接口中的操作。如果没有COM提供的正式实施,你的团队可能会“作弊” - 并在各层之间暴露无数的战术集成点,这可能导致性能问题。
如果你有扎实的项目管理和优秀的团队成员,那么你可以做的这些项目标准的执行不依赖于COM的手续。在C#中定义您自己的包装类,通过它发生所有跨界。
底线,我怀疑,是你不知道究竟是正确的决定,直到你玩它,并对其进行测试。
找几个团队成员,好开发人员,让他们建立两个不同选项的原型。例如,薄与厚,这些术语的确切含义由您定义。给他们3周左右的时间把东西放在一起。然后衡量他们的生产力和绩效,并据此作出决定。