C#比C++运行得更快?

Cor*_*urn 3 c# c++ optimization

我和朋友写了一个加密模块,我们希望将它移植到多种语言,这样它就不是特定于平台的加密.最初是用C#编写的,我把它移植到C++和Java中.C#和Java都将以大约40 MB/s的速度加密,但C++只能以大约20 MB/s的速度加密.为什么C++运行速度要慢得多?是因为我使用的是Visual C++吗?

我该怎么做才能加快我的代码速度?是否有更好的编译器可以更好地优化C++?

我已经尝试过优化代码本身,比如使用x >> 3代替x / 8(整数除法),或者y & 63代替y % 64和其他技术.如何以不同方式构建项目以使其在C++中更具性能?

编辑:

我必须承认,我没有研究过编译器如何优化代码.我将在大学里上课,致力于学习编译器和口译员.

至于我在C++中的代码,它并不是很复杂.有NO包括,有"基本"数学以及我们称之为"状态跳跃"以产生伪随机结果的东西.我们所做的最复杂的事情是在初始散列阶段实际执行加密和未经检查的乘法的按位运算.有动态分配的2D数组,它们在Encryption对象的生命周期内保持活跃状态​​(并在析构函数中正确释放).这里只有180行.好吧,所以我的微观优化不是必要的,但我应该相信它们不是问题,而是时间问题.要真正深入研究,这是程序中最复杂的代码行:

input [L + offset] ^ = state [state [SIndex ^ 255]&63];

我不是在移动数组,也不是在处理对象.

从语法上讲,整个代码集运行完美,如果我用C#加密某些内容并用C++或Java解密它,它将无缝地工作,所有3种语言都会按照你的预期进行交互.

我不一定希望C++比C#或Java(彼此在1 MB/s之内)运行得更快,但我确信有一种方法可以让C++以同样快的速度运行,或者至少比它更快现在.我承认我不是C++专家,我肯定不会像你们许多人那样经验丰富,但如果我能将99%的代码从C#剪切并粘贴到C++并让它在5中工作分钟,然后我有点说,执行需要两倍的时间.

重新编辑:我在Visual Studio中发现了一个我忘记设置的优化.现在C++的运行速度比C#快50%.感谢所有提示,我在研究中学到了很多关于编译器的知识.

Chr*_*ian 24

如果没有源代码,很难说出加密算法/程序的性能.我认为虽然你把它移植到C++时犯了一个"错误",这意味着你以低效的方式使用它(例如,大量的对象复制发生).也许你也使用过VC 6,而VC 9会产生更好的代码.

至于"x >> 3"优化......现代编译器确实将整数除法转换为位移位.不用说,这种优化可能根本不是你的程序的瓶颈.你应该首先剖析它,找出你花费大部分时间的地方:)


Gle*_*len 15

问题非常广泛.在C#中有效的东西在C++中效率可能不高,反之亦然.

您正在进行微优化,但是您需要检查解决方案的整体设计,以确保它在C++中有意义.重新设计解决方案的大部分内容以使其在C++中更好地工作可能是个好主意.

与性能相关的所有内容一样,首先分析代码,然后修改,然后再次分析.重复,直到达到可接受的性能水平.


Chr*_*her 13

在C#中"相对"快速的东西在C++中可能会非常慢.

您可以在C++中编写"更快"的代码,但您也可以编写更慢的代码.特别是在C++中,调试版本可能非常慢.因此,请查看编译器的优化类型.

大多数情况下,在移植应用程序时,C#程序员倾向于使用"创建一百万个新对象"方法,这确实使C++程序变慢.您可以重写这些算法以使用预先分配的数组,并使用紧密循环运行这些算法.

使用预先分配的内存,您可以利用C++的优势,通过将这些指针转换为正确的pod结构化数据来使用指向内存的指针.

但这实际上取决于您在代码中编写的内容.

因此,测量代码,看看实现烧掉最多cpu的位置,然后构造代码以使用正确的算法.


Dav*_*ley 7

你的计时结果绝对不是我所期望的用精心编写的C++和编写良好的C#.你几乎肯定会编写效率低下的C++.(或者,或者您没有使用相同类型的选项进行编译.确保您正在测试发布版本,并检查优化选项.

但是,像你提到的那样,微优化将不会有效地改善性能.你在浪费时间做编译器会为你做的事情.

通常,您首先查看算法,但在这种情况下,我们知道算法不会导致性能问题.我建议使用分析器来查看是否可以找到一个很大的时间接收器,但它可能找不到与C#或Java不同的东西.

我建议看一下C++与Java和C#的区别.对象有一件大事.在Java和C#中,对象的表示方式与C++指向对象的方式相同,尽管从语法中来看并不明显.

如果您正在使用Java和C++移动对象,那么您在Java中移动指针很快,而C++中的对象可能很慢.寻找使用中型或大型物体的位置.你把它们放在容器类中吗?这些类移动对象.将它们更改为指针(最好是智能指针,如std :: tr1 :: shared_ptr <>).

如果你没有C++经验(并且经验丰富且能干的C++程序员很可能不会被微观优化),那就试着找一个人.C++不是一种非常简单的语言,拥有比Java或C#更多的传统包袱,你可能会遗漏很多东西.


Dev*_*lar 7

将性能关键代码从一种语言"移植"到另一种语言通常是一个坏主意.您倾向于不使用目标语言(在这种情况下为C++)充分发挥潜力.

我见过的一些最糟糕的C++代码是从Java移植过来的.几乎所有东西都有"新" - 对Java来说是正常的,但对于C++来说肯定是性能杀手.

你通常最好不要移植,但重新实现关键部分.

  • 对.不知何故,当人们比较两种语言的表现时,它总是*证明他们最初编写代码的语言更快.这不应该让任何人感到惊讶,它只是意味着你的测试存在缺陷,但这绝不会阻止人们进行这些比较. (5认同)

Mar*_*ork 5

C#/ Java程序转换不好的主要原因(假设其他一切都是正确的).C#/ Java开发人员是不是正确地理解了对象和引用的概念.注意在C#/ Java中,所有对象都通过(相当于)指针传递.

Class Message
{
    char buffer[10000];
}

Message Encrypt(Message message)  // Here you are making a copy of message
{
    for(int loop =0;loop < 10000;++loop)
    {
        plop(message.buffer[loop]);
    }

    return message;  // Here you are making another copy of message
}
Run Code Online (Sandbox Code Playgroud)

要以(更多)C++样式重写它,您应该使用引用:

Message& Encrypt(Message& message)  // pass a reference to the message
{
   ...

    return message;  // return the same reference.
}
Run Code Online (Sandbox Code Playgroud)

C#/ Java程序员很难实现的第二件事是缺少垃圾收集.如果你没有正确释放任何内存,你可能会开始内存不足而且C++版本正在颠簸.在C++中,我们通常在堆栈上分配对象(即没有新的).如果对象的生命周期超出了方法/函数的当前范围,那么我们使用new,但是我们总是将返回的变量包装在智能指针中(以便正确删除它).

void myFunc()
{
    Message    m;
    // read message into m

    Encrypt(m);
}

void alternative()
{
    boost::shared_pointer<Message>  m(new Message);

    EncryptUsingPointer(m);
}
Run Code Online (Sandbox Code Playgroud)