为什么不在C#中使用非托管安全代码


10

C#中有一个选项可以执行未经检查的代码。通常不建议这样做,因为托管代码更加安全并且可以解决很多问题。

但是我想知道,如果您确定您的代码不会引起错误,并且您知道如何处理内存,那为什么(如果您喜欢快速代码)遵循一般建议?

我想知道这一点,因为我编写了一个用于摄像机的程序,该程序需要非常快速的位图处理。我自己制作了一些快速的图形算法,并且使用非托管代码在位图上效果很好。

现在,我通常会怀疑,如果您确定没有内存泄漏或崩溃的风险,为什么不更频繁地使用非托管代码?

PS我的背景:我有点涉足这个编程领域,而且我一个人工作(我从事了几年),所以我希望这个软件设计问题不会那么奇怪。我真的没有其他人像老师那样问这些事情。


8
unsafe意思是“知道自己在做什么,权衡利弊。” 我已经使用unsafe了很少的时间,并且总是针对与性能相关的特定问题,这些问题可以用自己的方法来解决。我不将其用作一般的编程技术,因为在大多数情况下,额外的性能优势不值得在安全性上有所损失。
罗伯特·哈维

14
这些年来,我写了很多代码,有时会崩溃或出现内存泄漏,我很确定没有内存泄漏或崩溃的风险。
whatsisname 2012年

1
这是一个很好的unsafe用例示例:stackoverflow.com/q/11660127/102937
Robert Harvey 2012年

3
我猜您的位图代码仍然存在错误,但您只是没有检测到它们。即使不是这种情况,也要等到必须在现有代码中实现一些新要求之后再进行。
Doc Brown

1
因为即使您确定代码不会导致错误,也仍然会导致错误。
user253751

Answers:


27

好吧,这主要是古老的格言

  • 不要优化
  • (仅适用于专家)尚未优化

但是实际上我可以想到避免不安全代码的三个主要原因。

  1. 错误:问题的关键部分是“如果您确定您的代码不会引起错误”。好吧,您怎么能完全确定呢?您是否使用带有证明方法正确的证明者?编程中肯定有一件事,那就是您将有错误。起飞安全装置时,您会允许新的错误爬过低谷。当您让垃圾收集器为您处理内存时,许多问题就消失了。

  2. 并非总是像您想的那样快:另一点是:根据问题,收益可能不会那么大。尽管我现在似乎找不到它们,但我记得Google进行了一项研究,比较了Java,Scala,Go和C ++的速度。一旦经过优化,C ++当然会更快。但是以“惯用”方式编程的算法实际上并没有那么快。从他们使用标准结构和习惯用法(stl容器,没有展开的循环等)的意义上讲,这是习惯用法。微软对C#和C ++进行了类似的实验。Microsoft高级工程师之一Raymond Chen必须编写自己的std :: string实现才能击败C#。(请参阅:http : //www.codinghorror.com/blog/2005/05/on-managed-code-performance-again.html)通过更少的工作,您在托管代码中获得了相当不错的性能,因此通常不值得为此烦恼。

  3. 可重用性:不安全代码只能在完全信任的环境中使用。例如,在ASP.NET服务器中,通常不能使用不安全的代码,因为通过缓冲区溢出很容易引入漏洞。另一个例子是clickonce。或者,如果您的应用程序是从网络共享访问的。因此,如果您打算在各种部署方案中使用代码,那么不安全的代码就不适合了。

基本上就是这样:它不赞成这样做,因为它可能会引入不必要的错误,可能根本没有收获,并且降低了代码的可重用性。

但是,如果您的方案确实需要性能(并且您有数据可以证明),那么您是一位经验丰富的程序员,知道如何处理内存,并且您的代码将在受控环境中使用,那么可以肯定地使用它。


4

从某种意义上说,非托管代码是一种付款方式:您可以通过额外的开发工作来提高执行速度。实际上,非托管代码需要更多时间来开发,调试和维护。对于大多数参与者而言,使其完全正确是一项挑战。从某种意义上讲,这类似于在汇编中进行编程:当然,如果在汇编中进行编写*,则可以从CPU中挤出更多的能量,但您会“花更多”的力气去做。

有时,开发时间的差异非常明显-天数而不是数小时。但是,执行速度的差异几乎没有那么大。这就是为什么开发非托管代码的原因是类似于您在您的帖子中所描述的情况-本地化,自包含的资源密集型算法的实现,例如音频和视频处理。

本质上,您的问题的答案类似于为什么每个人都不会驾驶法拉利的答案:这是一辆更好的汽车,对吗?不幸的是,并非所有人都能负担得起。


*过去几十年来,编译器优化技术的进步缩小了这一差距,以至于不再是肯定的选择。


0

因为对于命令性语言来说,“确定”正确性或数学意义上的任何其他约束(即您有证明)是一个非常困难的问题。程序通常具有大量状态,因此即使检查每个可能的状态也无法对其进行验证。创建建设性的证明不是您可以自动化的事情。

因此,原因是托管执行提供的保险最经常抵消了不安全代码带来的小小的性能提升。当然,这也取决于特定的用例。


1
我不认为这有什么与正确性或简单做的原因..
吉米·霍法

没有人在谈论正式的正确性证明。

1
我确定您的帖子没有讲到重点,但我没有提出正式的证明。同样,我可以确定我的程序是正确的(例如,经过广泛的测试,调试和长时间的实际使用,没有出现任何错误),而无需一劳永逸地证明它。这种解释与大多数人说“确保正确”的含义更接近。形式化方法是一个非常利基的问题,对于大多数开发人员来说完全没有考虑。

1
我没有这样的问题。正如我所读到的,这个问题是关于为什么不/不应该更频繁地使用来自托管世界的逃生舱口(这意味着默认使用托管代码是有意义的)。无论如何,如果您想回答问题(通过指出确保正确性的难点),则可以在不谈论绝对,正式的正确性保证的情况下这样做。到目前为止,您的答案仅围绕命令式语言正确性的完整,声音证明。但这太过分了,我认为有关托管C#的证据同样(或几乎一样)困难。

1
@fish:我明白你在说什么。难以证明的事物和难以推理的事物之间存在关联。如果很难证明是正确的,那么很难确定它是正确的。
迈克尔·肖

0

简而言之,没有什么可以阻止您在C ++环境中完成所有工作以及管理程序的细节。因为您非常确定可以在没有垃圾收集器的情况下正确管理所有的内存循环和泄漏,所以欢迎您使用C ++进行此操作:)

相反,C#具有提供安全/托管和强类型开发环境以在.NET Framework中安全运行的优势。

编程非托管代码的可能缺点是开发时间较长,需要分配时间进行详细测试。您当然可以提高处理速度,并更好地控制软件的运行方式。

因此,当您确定某些特定情况可能会使您受益于不使用它时,可以选择从4.0开始在.NET Framework中与非托管代码一起使用...


啊哈,那很有趣,您会看到我来自微控制器领域,通常都会编写像样的c ++,几乎没有错误的余地,而且软件的良好设计是关键要做的事情
user613326
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.