繁体   English   中英

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

[英]Performance gains in re-writing C# code in C/C++

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

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

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

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

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

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

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

如果您使用SqlDataReader (比如说)按顺序加载行,则应该可以尽快批量处理N行,并将其移交给单独的线程进行后处理,这是您当前头痛的问题所在。 如果你在.Net 4.0上这是最简单的使用任务并行库System.Collections.Concurrent也可用于线程之间的结果整理。

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

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

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

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

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

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

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

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

例如:上周我重写了(在C#中)一个大三学生写的课(也在C#中)。 我通过应用如果我用C写它(即考虑性能),我会用同样的方法实现了超过原码25倍的速度提升。 我实现了你所声称的相同的加速,而不必改为使用不同的语言。

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

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

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

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

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

让自己熟悉混合组件 - 这比Interop更好。 Interop是处理本机库的快速方法,但混合程序集的性能更好。
MSDN上的混合程序集
像往常一样,主要是测试和测量......

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

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

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

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

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

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

分析是查看所有CPU周期的第一步。

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

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

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

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

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

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

缩小Unicode支持有额外的好处,但只有你能够充分了解你的应用程序才能知道这是否安全。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM