我应该用C/C++或I';我擅长C#不安全指针

本文关键字:指针 不安全 C++ 我应该 | 更新日期: 2023-09-27 17:47:49

我目前正在编写一个C#应用程序,它可以进行大量的数字信号处理,其中涉及到许多小的微调内存xfer操作。我用不安全的指针编写了这些例程,它们的性能似乎比我最初想象的要好得多。然而,我希望这个应用程序尽可能快。

用C或C++重写这些例程会给我带来性能上的好处吗?还是应该坚持使用不安全的指针?我想知道与C/C++相比,不安全的指针在性能方面给表带来了什么。

编辑:我在这些例程中没有做任何特别的事情,只是做普通的DSP东西:缓存友好的数据从一个数组传输到另一个数组,途中会有很多乘法、加法、移位等。我希望C/C++例程看起来与它们的C#对应程序几乎相同(如果不完全相同的话)。

编辑:非常感谢大家的聪明回答。我学到的是,除非进行某种SSE优化,否则仅通过直接端口不会显著提高性能。假设所有现代C/C++编译器都能利用它,我期待着试一试。如果有人对结果感兴趣,请告诉我,我会把它们发布在某个地方。(不过可能需要一段时间)。

我应该用C/C++或I';我擅长C#不安全指针

实际上,我几乎完全按照您的要求做了,只是在图像处理领域。我从C#不安全指针开始,然后进入C++/CLI,现在我用C++编写所有内容。事实上,从那时起,我从C++中的指针变成了SSE处理器指令,所以我一直在努力。我还没有接触到汇编程序,虽然我不知道是否需要,但我在CodeProject上看到了一篇文章,文章显示SSE可以像内联汇编程序一样快,如果你愿意,我可以找到它。

在我前进的过程中,我的算法从C#中不安全指针的每秒1.5-2帧左右发展到了现在的每秒40帧。C#和C++/CLI肯定比C++慢,即使有指针,我也没能用这些语言达到每秒10帧以上。当我切换到C++时,我立刻得到了每秒15-20帧的速度。一些更巧妙的改变和SSE让我达到了每秒40帧。所以,是的,如果你想在我的经验中加快速度,这是值得的。有明显的性能提升。

优化DSP代码的另一种方法是使其缓存友好。如果你有很多滤波器要应用于你的信号,你应该将所有的滤波器应用于每个点,即你最内层的环路应该在滤波器上,而不是在数据上,例如:

for each n do t´[n] = h(g(f(t[n])))

通过这种方式,你可以减少缓存的垃圾,并且很可能获得很好的速度提升。

我认为你应该用C++(托管或非托管)或C#编写你的DSP例程,使用可靠的设计,但不需要从一开始就试图优化一切,然后你应该分析你的代码,找到瓶颈,并试着优化它们。

从一开始就试图生成"最佳"代码会分散你对编写工作代码的注意力。请记住,80%的优化只会影响20%的代码,因为在很多情况下,只有10%的代码会占用90%的CPU时间。(YMMV,因为它取决于应用程序的类型)

当我试图在我们的图形工具包中优化阿尔法混合的使用时,我首先尝试以"裸金属"的方式使用SIMD:内联汇编程序。很快,我发现使用SIMD内部函数比纯汇编更好,因为编译器能够通过重新排列各个操作码来进一步优化可读的C++内部函数,并最大限度地使用CPU中的不同处理单元。

不要低估编译器的威力!

我能获得任何性能优势吗在C/C中重写这些例程++还是应该坚持使用不安全的指针?

理论上,这并不重要——一个完美的编译器会将代码(无论是C还是C++)优化为尽可能好的汇编程序。

然而,在实践中,C几乎总是更快,尤其是对于指针类型的算法——它尽可能接近无需在汇编中编码的机器代码。

C++在性能方面没有带来任何好处——它是作为面向对象的C版本构建的,对程序员来说有更多的功能和易用性。虽然在某些方面,它会表现得更好,因为给定的应用程序将从面向对象的角度受益,但它并不意味着表现得更好——它旨在提供另一个抽象级别,以便更容易地编程复杂的应用程序。

因此,不,您可能不会看到通过切换到C++来提高性能。

然而,对你来说,找出答案可能比避免在上面花费时间更重要-我认为移植并分析它是一项有价值的活动。如果你的处理器有某些C++或Java使用指令,并且编译器知道这些指令,它可能能够利用C中不可用的功能。这是不可能的,但也是可能的。

然而,DSP处理器是出了名的复杂野兽,离组装越近,性能就越好(即,代码的手动调整越多)。C比C++更接近汇编。

-Adam

首先让我回答关于"安全"与"不安全"的问题:你在帖子中说"我希望应用程序尽可能快",这意味着你不想使用"安全"或"托管"指针(甚至不要提垃圾收集)。

关于您的语言选择:C/C++使您可以更轻松地处理底层数据,而不会产生与现在每个人都在使用的花哨容器相关的任何开销。是的,被容器拥抱是很好的,可以防止你出现断层。。。但是与容器相关联的更高级别的抽象RUINS您的性能。

在我的工作中,我们的代码必须运行得很快。一个例子是我们的多相重采样器,它可以处理指针和掩蔽操作以及定点DSP滤波。。。如果没有对内存的低级别控制和位操作===>,这些聪明的技巧都不可能实现,所以我说坚持使用C/C++。

如果你真的想聪明一点,把你所有的DSP代码都写在低级C中。然后把它和更安全的容器/托管指针混合在一起。。。当它达到速度时,你需要卸下训练轮。。。他们让你慢下来太多了。

(仅供参考,关于取下训练轮:你需要额外离线测试你的C DSP代码,以确保它们的指针使用良好……否则会出现故障。)

编辑:p.s."seg断层"是所有PC/x86开发人员的奢侈品。当您编写嵌入代码时。。。seg故障只意味着您的处理器将进入wuide,并且只能通过电源循环来恢复;)。

为了了解如何提高性能,最好了解可能导致瓶颈的代码部分。

由于您谈论的是小型内存传输,我认为所有数据都将放入CPU的缓存中。在这种情况下,你能获得的唯一收益就是知道如何处理CPU的内部。通常,最熟悉CPU内部函数的编译器是C编译器。因此,在这里,我认为您可以通过移植来提高性能。

另一个瓶颈是CPU和内存之间的路径——由于应用程序中的大量内存传输,缓存未命中。最大的收益将在于最大限度地减少缓存未命中,这取决于您使用的平台和数据的布局(它是本地的还是通过内存分布的?)。

但由于你已经在使用不安全的指针,你可以自己控制这一点,所以我的猜测是:在这方面,你不会从到C(或C++)的端口中受益太多。

最后:您可能想将应用程序的一小部分移植到C.

鉴于您已经在用不安全的代码编写,我认为将其转换为C dll并从C#中调用它们相对容易。在确定了程序中最慢的部分后执行此操作,然后用C.替换它们

你的问题在很大程度上是哲学性的。答案是:不要优化,直到你的个人资料。

你问自己是否会有所进步。好吧,你会提高N个百分点。如果这已经足够了(比如你需要在一些嵌入式系统上在20毫秒内执行200次的代码),你就可以了。但如果这还不够呢?

你必须先测量一下,然后发现代码的某些部分是否可以用相同的语言但更快地重写。也许您可以重新设计数据结构以避免不必要的计算。也许你可以跳过一些内存重新分配。也许有些事情是用二次复杂度做的,而它可以用线性复杂度做。在你测量过它之前,你不会看到它。这通常比用另一种语言重写所有内容浪费的时间要少得多。

C#不支持SSE(目前,有一个用于SSE操作的单一项目)。因此,使用SSE的C/C++肯定会更快。

但是,您必须小心从托管到本机和从本机到托管的转换,因为它们非常昂贵。在任何一个世界呆尽可能长的时间。

你真的希望应用程序尽可能快还是足够快?那个告诉你下一步该做什么。

如果你坚持使用手动滚动,而没有在汇编程序或类似程序中进行手动优化,那么C#应该没问题。不幸的是,这种问题只有通过实验才能真正得到答案。您已经处于非托管指针空间中,所以我的直觉是,直接端口到C++在速度上不会有显著差异。

不过,我应该说,我最近也遇到了类似的问题,在尝试了"英特尔集成性能原件"库后,我们最终放弃了手卷。我们在那里看到的性能改进非常令人印象深刻。

Mono 2.2现在支持SIMD。有了SIMD,您可以同时获得最佳的托管代码和原始速度。

你可能还想看看在c#中使用SSE,这可能吗?

我建议,如果您的DSP代码中有任何算法需要进行优化,那么您应该真正用汇编语言编写它们,而不是用C或C++。

一般来说,对于现代处理器和硬件,没有那么多场景需要或保证进行优化。您是否确实发现了任何性能问题?如果没有,那么最好还是坚持你所拥有的。在大多数简单算术的情况下,不安全的C#不太可能比C/C++慢很多。

您是否考虑过C++/CLI?那时你可以两全其美。如果需要,它甚至允许您使用内联汇编程序。