代码之家  ›  专栏  ›  技术社区  ›  Flinkman

函数调用的成本是多少?

  •  31
  • Flinkman  · 技术社区  · 18 年前

    相比于

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

    在Windows上的C++。

    15 回复  |  直到 18 年前
        1
  •  27
  •   mfx    18 年前

    相对计时(不应超过100的系数;-)

    • 缓存中的内存访问=1
    • 缓存中的函数调用/返回=2
    • 缓存外的内存访问=10..三百
    • 磁盘访问=1000..1E8(根据传输的字节数分摊)
      • 主要取决于搜寻时间
      • 转移本身可以很快
      • 至少涉及几千个操作,因为必须至少跨越用户/系统阈值两次;必须计划I/O请求,必须写回结果;可能分配了缓冲区…
    • 网络呼叫=1000..1E9(根据传输的字节数分摊)
      • 与磁盘I/O相同的参数
      • 原始传输速度可能很高,但另一台计算机上的某些进程必须完成实际工作。
        2
  •  19
  •   jW.    18 年前

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

    与时间相比

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

        3
  •  8
  •   Ferruccio    18 年前

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

    与其他列出的事物相比-数量级更少。

    对于任何操作系统上的任何语言,这都应该是正确的。

        4
  •  4
  •   Torlack    18 年前

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

    对于其他一切,函数调用的速度都快很多(许多)。

        5
  •  3
  •   James Curran    18 年前

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

    首先,“简单内存访问”并不简单。因为在现代时钟速度下,CPU从芯片的一边到另一边(光速——这不仅是一个好主意,而且是规律)增加两个数字的速度比它得到一个数字的速度快。

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

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

        6
  •  3
  •   Steve Jessop    18 年前

    假设您指的是调用本身的开销,而不是被调用方可能做的事情,那么它肯定远比除“简单”内存访问之外的所有方法都快。

    它可能比内存访问慢,但请注意,由于编译器可以进行内联,函数调用开销有时为零。即使不是这样,至少在某些体系结构上,对指令缓存中已有代码的某些调用可能比访问主(未缓存)内存更快。这取决于在调用之前需要将多少寄存器溢出到堆栈中,诸如此类。请参考编译器和调用约定文档,尽管您不可能比分解发出的代码更快地找到它。

    另外请注意,有时“简单”的内存访问不是这样的——如果操作系统必须从磁盘导入页面,那么您就需要等待很长时间。如果您跳到当前在磁盘上调出的代码中,情况也是如此。

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

        7
  •  2
  •   user286602    16 年前

    这个链接在谷歌中有很多。为了将来的参考,我用C语言运行了一个关于函数调用成本的简短程序,答案是:“大约是内联成本的六倍”。以下是详细信息,请参见底部的//输出。更新:为了更好地比较苹果和苹果,我更改了class1.method以返回“void”,因此:public void method1()//返回0;
    不过,inline的速度快了2倍:inline(avg):610毫秒;函数调用(avg):1380毫秒。因此,更新后的答案是“大约两次”。

    使用系统; 使用system.collections.generic; 使用system.linq; 使用system.text; 使用System.Diagnostics;

    命名空间函数调用开销 { 类程序 { 静态void main(string[]args) { debug.writeline(“stop1”); int imax=100000000;/100米 datetime 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");
    
    
        }
    }
    

    //类1 使用系统; 使用system.collections.generic; 使用system.linq; 使用system.text;

    命名空间函数调用开销 { 班级一班 {

        public Class1()
        {
        }
    
        public int Method1 ()
        {
            return 0;
        }
    }
    

    }

    //输出: 停止1 主功能运行时间(ms)为:595 停止2 helper类函数的运行时间(ms)为:3780

    停止1 主功能运行时间(ms)为:592 停止2 助手类函数(ms)的运行时间为:4042

    停止1 主功能运行时间(ms)为:626 停止2 helper类函数的运行时间(ms)为:3755

        8
  •  1
  •   Pete    18 年前

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

        9
  •  1
  •   MSalters    18 年前

    让我们不要忘记C++具有虚拟调用(明显更昂贵,关于X10),在Windows上,你可以期待VS来内嵌调用(0的代价是定义,因为二进制中没有调用)。

        10
  •  0
  •   Nick Craver    18 年前

    取决于这个函数的功能,如果它对内存中的对象进行逻辑处理,它将在您的列表中排名第二。如果包括磁盘/网络访问,请在列表中进一步列出。

        11
  •  0
  •   coppro    18 年前

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

        12
  •  0
  •   Kent Fredric    18 年前

    如果函数在编译时是内联的,那么函数的开销将等于0。

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

    当然,当我这样写的时候,这听起来非常明显。

        13
  •  0
  •   Dark Shikari    18 年前

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

        14
  •  0
  •   Adi    18 年前

    函数调用实际上是参数到堆栈(多内存访问)、寄存器保存、实际代码执行以及最终结果复制和寄存器恢复(寄存器保存/恢复取决于系统)的副本。

    所以…相对而言:

    • 函数调用>简单内存访问。
    • 函数调用<<磁盘访问-与内存相比,它可能要贵上百倍。
    • 另一台计算机上的功能调用<<内存访问-网络带宽和协议是这里的大杀手。
    • 在另一台计算机上进行函数调用<<<磁盘访问-以上所有内容及更多内容:)
        15
  •  0
  •   INS    18 年前

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

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