36

相比

  • 简单的内存访问
  • 磁盘访问
  • 另一台计算机上的内存访问(在同一网络上)
  • 另一台计算机上的磁盘访问(在同一网络上)

在 Windows 上的 C++ 中。

4

15 回答 15

30

相对时间(不应该超过 100 倍 ;-)

  • 缓存中的内存访问 = 1
  • 缓存中的函数调用/返回 = 2
  • 缓存外的内存访问 = 10 .. 300
  • 磁盘访问 = 1000 .. 1e8(摊销取决于传输的字节数)
    • 主要取决于寻道时间
    • 传输本身可以非常快
    • 涉及至少几千个操作,因为用户/系统阈值必须至少超过两次;一个 I/O 请求必须被调度,结果必须被写回;可能分配了缓冲区...
  • 网络调用 = 1000 .. 1e9(摊销取决于传输的字节数)
    • 与磁盘 i/o 相同的参数
    • 原始传输速度可能相当高,但另一台计算机上的某些进程必须完成实际工作
于 2008-09-18T18:07:01.420 回答
19

函数调用只是将内存中的帧指针转移到堆栈上,并在其上添加一个新帧。函数参数被移入本地寄存器以供使用,堆栈指针前进到堆栈的新顶部以执行函数。

与时间相比

函数调用~简单的内存访问
函数调用<磁盘访问
函数调用<另一台计算机上的内存访问函数调用<另一台计算机
上的磁盘访问

于 2008-09-18T17:43:55.877 回答
8

与简单的内存访问相比 - 稍微多一点,真的可以忽略不计。

与列出的其他所有内容相比 - 数量级少。

这应该适用于任何操作系统上的几乎任何语言。

于 2008-09-18T17:42:44.397 回答
4

一般来说,函数调用会比内存访问稍慢,因为它实际上必须进行多次内存访问才能执行调用。例如,在 x86 上使用 __stdcall 的大多数函数调用都需要多次推送和弹出堆栈。但是,如果您的内存访问甚至不在 L2 缓存中的页面,如果目标和堆栈都在 CPU 的内存缓存中,则函数调用会快得多。

对于其他一切,函数调用要快很多(很多)数量级。

于 2008-09-18T17:44:32.893 回答
3

很难回答,因为涉及的因素很多。

首先,“简单内存访问”并不简单。由于在现代时钟速度下,CPU 可以将两个数字相加,而不是从芯片的一侧到另一侧获得一个数字(光速——这不仅仅是一个好主意,它是定律)

那么,函数是在 CPU 内存缓存中调用的吗?您是否也在比较它的内存访问?

然后我们有函数调用将清除 CPU 指令流水线,这将以非确定性的方式影响速度。

于 2008-09-18T17:47:19.690 回答
3

假设您的意思是调用本身的开销,而不是被调用者可能会做的事情,那么它肯定比“简单”内存访问要快得多。

它可能比内存访问慢,但请注意,由于编译器可以进行内联,因此函数调用开销有时为零。即使不是,至少在某些架构上,对指令缓存中已经存在的代码的某些调用可能比访问主(未缓存)内存更快。这取决于在进行调用之前需要将多少寄存器溢出到堆栈,等等。请查阅您的编译器和调用约定文档,尽管您不太可能比反汇编发出的代码更快地弄清楚它。

另请注意,有时不是“简单”的内存访问 - 如果操作系统必须从磁盘导入页面,那么您将等待很长时间。如果您跳转到当前在磁盘上分页的代码,情况也是如此。

如果根本的问题是“我什么时候应该优化我的代码以最小化函数调用的总数?”,那么答案是“非常接近永远”。

于 2008-09-18T17:53:44.777 回答
2

这个链接在谷歌中出现了很多。为了将来参考,我在 C# 中运行了一个关于函数调用成本的简短程序,答案是:“大约是内联成本的六倍”。以下是详细信息,请参阅底部的//输出。更新:为了更好地比较苹果和苹果,我将 Class1.Method 更改为 return 'void',如下所示: public void Method1 () { // return 0; 尽管如此,内联速度还是快了 2 倍:内联(平均)
:610 毫秒;函数调用(平均):1380 毫秒。因此,更新后的答案是“大约两倍”。

使用系统;使用 System.Collections.Generic;使用 System.Linq;使用 System.Text;使用 System.Diagnostics;

命名空间 FunctionCallCost { 类程序 { 静态无效 Main(string[] args) { Debug.WriteLine("stop1"); int iMax = 100000000; //100M 日期时间 funcCall1 = DateTime.Now; 秒表 sw = Stopwatch.StartNew();

        for (int i = 0; i < iMax; i++)
        {
            //gives about 5.94 seconds to do a billion loops, 
          // or 0.594 for 100M, about 6 times faster than
            //the method call.
        }

        sw.Stop(); 

        long iE = sw.ElapsedMilliseconds;

        Debug.WriteLine("elapsed time of main function (ms) is: " + iE.ToString());

        Debug.WriteLine("stop2");

        Class1 myClass1 = new Class1();
        Stopwatch sw2 = Stopwatch.StartNew();
        int dummyI;
        for (int ie = 0; ie < iMax; ie++)
        {
          dummyI =  myClass1.Method1();
        }
        sw2.Stop(); 

        long iE2 = sw2.ElapsedMilliseconds;

        Debug.WriteLine("elapsed time of helper class function (ms) is: " + iE2.ToString());

        Debug.WriteLine("Hi3");


    }
}

// 这里使用 System 1 类;使用 System.Collections.Generic;使用 System.Linq;使用 System.Text;

命名空间 FunctionCallCost { 类 Class1 {

    public Class1()
    {
    }

    public int Method1 ()
    {
        return 0;
    }
}

}

// 输出:stop1 main 函数的运行时间(ms)是:595 stop2 helper 类函数的运行时间(ms)是:3780

stop1 main 函数的运行时间(ms)是:592 stop2 helper 类函数的运行时间(ms)是:4042

stop1 main 函数的运行时间(ms)是:626 stop2 helper 类函数的运行时间(ms)是:3755

于 2010-03-04T20:36:54.267 回答
1

实际调用函数但没有完全执行它的成本?还是实际执行该功能的成本?简单地设置一个函数调用并不是一项昂贵的操作(更新 PC?)。但显然,一个函数完全执行的成本取决于该函数在做什么。

于 2008-09-18T17:48:55.723 回答
1

我们不要忘记 C++ 有虚拟调用(明显更贵,大约 x10),在 WIndows 上,您可以期望 VS 内联调用(定义为 0 成本,因为二进制文件中没有剩余调用)

于 2008-09-19T11:28:43.023 回答
0

取决于该函数的作用,如果它对内存中的对象执行逻辑,它将在您的列表中排名第二。如果它包括磁盘/网络访问,则在列表的下方。

于 2008-09-18T17:42:35.940 回答
0

一个函数调用通常只涉及几个内存副本(通常是到寄存器中,因此它们不应该占用太多时间),然后是一个跳转操作。这将比内存访问慢,但比上面提到的任何其他操作都快,因为它们需要与其他硬件进行通信。在任何操作系统/语言组合上通常都应如此。

于 2008-09-18T17:46:22.873 回答
0

如果函数在编译时内联,则函数的成本等于 0。

0 当然是,如果没有函数调用,你会得到什么,即:自己内联它。

当我这样写时,这当然听起来太明显了。

于 2008-09-18T17:46:42.437 回答
0

函数调用的成本取决于架构。x86 相当慢(几个时钟加上每个函数参数一个时钟左右),而 64 位则要慢得多,因为大多数函数参数是在寄存器中传递的,而不是在堆栈中传递的。

于 2008-09-18T18:10:54.873 回答
0

函数调用实际上是将参数复制到堆栈上(多次内存访问),寄存器保存,实际代码执行,最后是结果复制和寄存器恢复(寄存器保存/恢复取决于系统)。

所以..相对来说:

  • 函数调用 > 简单内存访问。
  • 函数调用 << 磁盘访问 - 与内存相比,它可能要贵数百倍。
  • 函数调用 << 另一台计算机上的内存访问 - 网络带宽和协议是这里的重要时间杀手。
  • 函数调用<<<另一台计算机上的磁盘访问-以上所有以及更多:)
于 2008-09-18T19:07:19.530 回答
0

只有内存访问比函数调用快。

但是,如果编译器具有内联优化(对于 GCC 编译器,并且不仅在使用优化级别 3 (-O3) 时激活),则可以避免调用。

于 2008-09-18T19:10:23.843 回答