C#Native Interop - 为什么大多数库使用LoadLibrary和委托代替SetDllDirectory和简单的DllImport

问题描述 投票:12回答:1

有一个关于如何在运行时为great answer on SO设置搜索目录的DllImport。使用两行代码可以正常工作。

但是,许多开源项目改为使用LoadLibrary函数。有传言称通过委托调用本机方法的速度较慢。我把它们称为“谣言”,因为我只在两个地方看过这个,这无论如何都是微观优化。

最有趣的地方是这篇博文:http://ybeernet.blogspot.com/2011/03/techniques-of-calling-unmanaged-code.html

在那里,作者测量了不同技术的表现:

  • C#(资料性)4318毫秒
  • PInvoke - 抑制安全性5415 ms
  • Calli指令5505毫秒
  • C ++ / CLI 6311 ms
  • 功能委托 - 抑制安全性7788 ms
  • PInvoke 8249 ms
  • 功能代表11594ms

NNanomsg使用功能代表,但在this line上提到评论“这对传统P / Invoke的性能影响显然不好”的博客文章。

来自MSFT的ASP vNext的Kestrel server使用与Libuv库相同的技术:here is the code

我认为代理使用比简单的DllImport更麻烦,并且考虑到性能差异,我想知道为什么面向性能的库使用委托代替设置dll搜索文件夹?

是否有任何技术原因,如安全性,灵活性或其他 - 或者这仅仅是品味问题?我不明白其基本原理 - 作者是否可能没有足够的搜索StackOverflow!?

c# .net interop pinvoke
1个回答
9
投票

Hmya,博客文章,从根本上证明了分发技术信息的方式。如果我们能投票支持,世界将会变得更加美好。作者正在比较苹果和橘子。好吧,更像是苹果和自行车。

这里比较了两种根本不同的互操作方案。第一个是“普通”的,一个托管程序在非托管DLL中调用代码。使用[DllImport]属性或C ++ / CLI是首选武器。在CLR内部进行了高度优化,它动态生成机器代码,用于转换参数并进行调用。重要的是,托管程序总是运行大量非托管代码,因为它运行在纯粹的非托管操作系统之上。

你在说什么,“慢”版本,正在走另一条路。从非托管程序调用托管代码。有人称之为“反向pinvoke”。它更复杂,因为在您调用托管代码之前,首先必须加载并初始化CLR。并创建一个appdomain。并找到并加载包含代码的.NET程序集。 JIT编译它。

有三种基本方法可以做到这一点:

  • 自定义托管CLR。这是迄今为止最强大的版本。您可以使用托管接口显式创建CLR实例,并完全控制其配置。 CLRRuntimeHost COM coclass是让球滚动的主要工具。
  • 通过为它们提供[ComVisible(true)]属性,将.NET类公开为COM组件。非常简单,非托管代码完全没有意识到它实际上正在使用.NET代码。加载默认CLR主机,COM组件的注册表项指向mscoree.dll,mscoree.dll根据需要引导CLR。唯一的缺点是非托管代码作者需要编写COM客户端代码,这是一种迷失的技能。
  • 你在谈论什么,利用C ++ / CLI编译器生成DLL导出的能力。值得注意的是,Robert Gieseke的Unmanaged Exports工具使用了完全相同的技术,但通过重写程序集注入了这些DLL导出。

第三种方式有很大的缺点,超出了通话费用。它扩展性很差,必须显式导出每个方法,并且它必须是静态的,因此您无法实现对象模型。而这种超级糟糕,可怕,令人讨厌,不可能解决的问题是,当呼叫失败时,你无法获得任何诊断。托管代码喜欢抛出异常,如果不是来自代码本身,那么就是试图告诉您传递错误参数或无法准备代码的CLR。您无法看到这些异常,无​​法判断函数是否失败,也无法告诉失败的原因。如果非托管代码没有捕获具有非标准__try / __除关键字的SEH异常,则程序会发生炸弹。没有任何诊断。即使它确实赶上了SEH,你也只会得到一个“它没有工作”的信号。

必须编写以这种方式调用的托管代码来处理此问题。它必须在public方法中包含try / catch-em-all。并记录异常并提供返回错误代码的方法,以便调用者可以检测到故障。然而,遗漏的依赖DLL或版本问题等严重问题根本无法诊断。对于非托管代码作者来说,简单的LoadLibrary + GetProcAddress看起来很容易,但它却是一个长期的支持噩梦。

© www.soinside.com 2019 - 2024. All rights reserved.