在C / C ++中重写C#代码的性能提升

时间:2010-11-17 11:03:45

标签: c# c++ c multithreading performance

我写了一个程序的一部分,用C#中的字符串做了一些繁重的工作。我最初选择C#不仅因为它更容易使用.NET的数据结构,而且因为我需要使用该程序来分析数据库中的大约2-3百万条文本记录,并且使用C#连接到数据库要容易得多

该程序的一部分正在减慢整个代码的速度,我决定用C语言重写它,使用指针来访问字符串中的每个字符,现在代码的一部分花了大约119秒来分析C#中的10,000,000个字符串只需5秒即可获得C代码!性能是一个优先级,所以我正在考虑用C重写整个程序,将它编译成一个dll(当我开始编写程序时我不知道该怎么做)并使用C#中的DllImport来使用它的方法来工作使用数据库字符串。

考虑到重写整个程序需要一些时间,因为使用DllImport来处理C#的字符串需要编组等等,我的问题是C dll更快的字符串处理的性能提升将超过必须的性能损失。反复编组字符串以从C#访问C dll?

9 个答案:

答案 0 :(得分:10)

一种选择是将C代码重写为不安全的C#,它应该具有大致相同的性能,并且不会产生任何互操作性惩罚。

答案 1 :(得分:10)

首先,分析您的代码。您可能会发现一些真正的headmacker可以大大加快C#代码的速度。

其次,使用指针在C中编写代码并不是一个公平的比较。如果您打算使用指针,为什么不用汇编语言编写它并获得真正的性能呢? (不是真的,只是 reductio ad absurdam 。)对本机代码的更好比较是使用std::string。这样你仍然可以从string类和C ++异常安全中获得很多帮助。

鉴于您必须从数据库中读取2-3百万条记录来完成这项工作,我非常怀疑破解字符串所花费的时间将超过已用时间加载时间来自DB的数据。因此,请考虑如何构建代码,以便在数据库负载正在进行时开始字符串处理。

如果使用SqlDataReader(比如说​​)按顺序加载行,应该可以尽可能快地批量处理N行,然后切换到一个单独的线程进行当前的后处理头痛和这个问题的原因。如果您使用的是.Net 4.0,使用Task Parallel Library最简单,System.Collections.Concurrent也可用于对线程之间的结果进行整理。

这种方法应该意味着DB延迟和字符串处理都不是一个显示停止的瓶颈,因为它们并行发生。这适用于,即使您使用的是单处理器计算机,因为您的应用程序可以在等待下一批数据通过网络从数据库返回时处理字符串。如果您发现字符串处理最慢,请使用更多线程(即Task s)。如果数据库是瓶颈,那么您必须查看外部方法以提高其性能 - 数据库硬件或架构,网络基础架构。如果在处理更多数据之前需要掌握一些结果,TPL允许在Task s和协调线程之间创建依赖关系。

我的观点是,我怀疑在本地C或其他任何地方重新设计整个应用程序的痛苦是值得的。有很多方法可以给这只猫上皮。

答案 2 :(得分:4)

没有理由用C语言编写C ++,并且C / C ++不存在。

编组的性能影响非常简单。如果你必须单独编组每个字符串,那么你的表现会很糟糕。如果你可以在一个电话中整理所有一千万个字符串,那么编组根本不会产生任何影响。 P / Invoke不是世界上最快的操作,但是如果你只调用它几次,那就没关系了。

用C ++重新编写核心应用程序然后使用C ++ / CLI将其与C#数据库端合并可能更容易。

答案 3 :(得分:3)

这里有一些非常好的答案,尤其是@Steve Townsend's。

然而,我觉得值得强调一个关键点:从根本上说,没有理由为什么C代码“会比C#代码更快”。这个想法是一个神话。在引擎盖下,它们都生成在同一CPU上运行的机器代码。只要你不要求C#做比,那么它也可以表现得更好。

通过切换到C,你强迫自己更节俭(你避免使用托管字符串,边界检查,垃圾收集,异常处理等高级功能,并简单地将你的字符串视为原始字节块)。如果您将这些低级技术应用于C#代码(即将数据视为原始字节块,就像在C中那样),您会发现速度差异要小得多。

例如:上周我重写了(在C#中)一个大三学生写的课(也在C#中)。通过应用与相同的方法,我实现了比原始代码快25倍的速度,如果我在C中编写它(即思考关于性能)。我达到了你所声称的相同速度,而不必改为使用其他语言。

最后,仅仅因为一个孤立的案例可以快24倍,这并不意味着你可以通过将它全部移植到C来使你的整个程序全速提高24倍。正如史蒂夫所说的那样,对它进行分析以找出它慢的地方,只有在能够带来显着效益的地方,你才会付出努力。如果你盲目地转换为C,你可能会发现你花了很多时间使一些已经工作的代码更难以维护。

(PS我的观点来自29年编写汇编程序,C,C ++和C#代码的经验,并且理解该语言只是生成机器代码的工具 - 在C#vs C ++ vs C的情况下,它是主要是程序员的技能,而不是使用的语言,决定代码是快速还是慢速运行.C / C ++程序员往往比C#程序员更好,因为他们必须 - C#允许你懒惰并快速编写代码虽然C / C ++会让你做更多的工作而代码需要更长的时间来编写。但是一个优秀的程序员可以从C#中获得很好的性能,而一个糟糕的程序员可以从C / C ++中榨取糟糕的性能)

答案 4 :(得分:2)

由于字符串在.NET中是不可变的,我毫不怀疑优化的 C实现将胜过优化的 C#实现 - 毫无疑问!

P / Invoke确实会产生开销,但是如果你在C中实现大部分逻辑并且只为C#公开非常精细的API,我相信你的状态要好得多。

在一天结束时,用C语言编写实现意味着需要更长时间 - 但如果您准备好额外的开发成本,这将为您提供更好的性能。

答案 5 :(得分:2)

让自己熟悉混合组件 - 这比Interop更好。 Interop是处理本机库的快速通道方式,但混合组件表现更好 Mixed assemblies on MSDN
像往常一样,主要的是测试和测量...

答案 6 :(得分:0)

对于长字符串或多个字符串的连接,请始终使用StringBuilder。并不是每个人都知道,StringBuilder不仅可以用来更快地连接字符串,还可以用来插入,删除和替换字符。

如果这对你来说不够快,你可以使用 char-或byte-arrays 而不是字符串来操作它们。如果您已完成操作,则可以将数组转换回字符串。

C#中还有一个选项可以使用不安全的代码来获取指向字符串的指针并修改其他不可变的字符串,但我不会真的推荐这个。

正如其他人所说,你可以使用托管C ++ (C ++ / CLI)在.NET和托管代码之间进行良好的互操作。

您介意向我们展示代码,也许还有其他优化选项吗?

答案 7 :(得分:0)

当您开始在后期阶段优化程序时(编写应用程序时没有考虑优化),您必须确定瓶颈。

分析是了解所有CPU周期的第一步。

请记住,C#分析器只会分析您的.Net应用程序 - 不是内核中实现的IIS服务器,也不是网络堆栈。

这可能是一个看不见的瓶颈,在你努力取得进步时,你所关注的是几个数量级。

你认为你对作为内核驱动程序实现的IIS没有任何影响 - 你是对的。

但是你可以没有它 - 并且节省了大量的时间和金钱。

将你的才能放在可以发挥作用的地方 - 而不是你被迫用脚绑在一起的地方。

答案 8 :(得分:0)

固有的差异通常是2倍的CPU,5倍的内存。在实践中,很少有人能够很好地利用C ++来获得好处。

在支持Unicode的过程中获得额外的收益,但只有你能够充分了解你的应用程序才能知道这是否安全。

首先使用探查器,确保没有I / O限制。