优化(C语言):多个函数调用与一个函数调用

优化(C语言):多个函数调用与一个函数调用,c,optimization,function-calls,C,Optimization,Function Calls,例如,我想创建一个函数(insertNode),将节点添加到列表中。每次我想添加一个节点时,调用insertNode,或者将所有节点存储在一个数组中,通过将数组作为参数传递给函数,只调用一次insertNode,让函数完成其余的工作,是不是更快 代码示例: typedef struct Data { int *myArray; //the array where all integers are stored int firstAvailablePos;

例如,我想创建一个函数(
insertNode
),将节点添加到列表中。每次我想添加一个节点时,调用
insertNode
,或者将所有节点存储在一个数组中,通过将数组作为参数传递给函数,只调用一次
insertNode
,让函数完成其余的工作,是不是更快

代码示例:

typedef struct Data {
    int *myArray;             //the array where all integers are stored
    int firstAvailablePos;    //the first free position of myArray
} Data;

insertNode(Data *data, int newNum) {
    (data->myArray)[data->firstAvailablePos] = newNum;
    (data->firstAvailablePos)++;
}

alt_insertNode(Data *data, int *array, int arraySize) {
    int i;
    for(i = 0; i < arraySize; i++)
         (data->myarray)[i] = array[i];
}
  • 单函数调用

    anArraySize = 0;
    while (...) {
        ...
        anArray[i] = newNum;
        anArraySize++;
        ...
    }
    alt_insertNode(data, anArray, anArraySize);
    

  • 这将取决于程序中的许多内容。具体来说,节点是通过某种算法排序的,还是顺序不重要?如果是这样的话,传递数组节点或单独插入不会有太大的区别(对块或信息进行排序和将节点插入到排序位置应该是等效的)


    你也可以考虑程序中的哪些节点需要插入到列表中。如果列表使用动态内存,则需要在需要时沿线路插入节点。

    这取决于基线列表实现的结构。如果这是一个数组,并且insertNode附加了它,那么它会被复制到内存中的一个新位置,在这个位置上有更多的可用空间,以便新元素也可以放入。新元素也得到了memcpyd。这很快,因为它发生在内核中,而不是在用户空间程序中

    另一方面,如果你有类似链表的东西,其中以数组形式存储指向其他列表的指针。这样,您甚至不必复制列表中的所有元素,只需插入一个指向链接列表的新指针,该指针指向包含新元素的数组。那太快了


    从我目前所知道的情况来看,最好的答案是:这取决于调用代码的样子。

    这取决于调用代码的样子,但一般来说,如果短函数调用可以内联,则开销为零。创建一个临时数组只是为了避免函数调用开销几乎肯定是一个错误——但在某些情况下,像这样的“批处理”可以避免一系列每次插入的开销,而且可能有意义


    同时尝试和基准测试。

    函数调用比迭代花费的时间更长。如果通过调用insertNode函数插入节点,则需要一些迭代(取决于要插入的位置)才能在列表中插入该节点,但如果要插入大量节点,则每次都需要调用该函数。这可能会耗费时间

    如果通过将某个节点放入数组并最后调用insertNode将数组的节点复制到列表中来插入节点。这次insertNode的调用时间将减少,但交互次数将增加。这不会像函数调用那样耗费时间


    这里需要注意的一点是,阵列需要额外的内存。

    您的代码有问题:

    • 函数定义使用过时的语法。隐式返回类型在现代C代码中不再受支持,您应该将其指定为
      void

    • 使用额外的括号会使代码看起来很尴尬

    • 函数
      insertNode
      不检查
      myArray
      指向的数组是否足够大。如果需要,您应该检查并重新分配阵列

    • 函数
      alt\u insertNode
      不检查可用空间,也不更新
      firstAvailablePos

    根据您的重新分配方案和允许编译器优化的程度,成批插入值可能比逐个插入值更有效,尤其是如果您不使用
    malloc()
    分配中间数组。对特定测试用例进行基准测试将告诉您哪一个更有效。然而,请注意,使代码尽可能简单是很有价值的

    下面是一个更完整的实现,可用于运行测试:

    typedef struct Data {
        int *myArray;             // the array where all integers are stored
        size_t size;              // the number of int that can be stored
        size_t firstAvailablePos; // the first free position of myArray
    } Data;
    
    /* reallocating the array with a simple exponential growth */
    int insertNode(Data *data, int newNum) {
        if (data->firstAvailablePos == data->size) {
            size_t newSize = (data->size < 32) ? 32 : data->size + data->size / 2;
            int *array = realloc(myArray, newSize * sizeof(*array));
            if (array == NULL)
                return -1;
            data->myArray = array;
            data->size = newSize;
        }
        data->myArray[data->firstAvailablePos++] = newNum;
        return 0;
    }
    
    int alt_insertNode(Data *data, int *array, size_t arraySize) {
        if (data->firstAvailablePos + arraySize > data->size) {
            size_t newSize = (data->size < 32) ? 32 : data->size + data->size / 2;
            while (newSize < data->firstAvailablePos + arraySize) {
                newSize += newSize / 2;
            }
            int *array = realloc(myArray, newSize * sizeof(*array));
            if (array == NULL)
                return -1;
            data->myArray = array;
            data->size = newSize;
        }
        memcpy(data->myArray + data->firstAvailablePos, array, arraySize * sizeof(*array));
        data->firstAvailablePos += arraySize;
        return 0;
    }
    
    typedef结构数据{
    int*myArray;//存储所有整数的数组
    size\u t size;//可以存储的int数
    size\u t firstAvailablePos;//myArray的第一个可用位置
    }数据;
    /*以简单的指数增长重新分配阵列*/
    int insertNode(数据*Data,int newNum){
    如果(数据->第一个可用EPOS==数据->大小){
    大小\u t新闻大小=(数据->大小<32)?32:数据->大小+数据->大小/2;
    int*array=realloc(myArray,newSize*sizeof(*array));
    if(数组==NULL)
    返回-1;
    数据->myArray=array;
    数据->大小=新闻大小;
    }
    data->myArray[data->firstAvailablePos++]=newNum;
    返回0;
    }
    int alt_insertNode(数据*数据,int*数组,大小\u t数组大小){
    如果(数据->第一个可用项+阵列大小>数据->大小){
    大小\u t新闻大小=(数据->大小<32)?32:数据->大小+数据->大小/2;
    而(新闻大小firstAvailablePos+arraySize){
    newSize+=newSize/2;
    }
    int*array=realloc(myArray,newSize*sizeof(*array));
    if(数组==NULL)
    返回-1;
    数据->myArray=array;
    数据->大小=新闻大小;
    }
    memcpy(data->myArray+data->firstAvailablePos,array,arraySize*sizeof(*array));
    data->firstAvailablePos+=阵列化;
    返回0;
    }
    
    将代码发布到您的两种方法中会产生更好的具体反馈。这取决于您必须选择的每种方法在列表中添加一项的单独成本。你能测量一下吗?或者发布代码,让我们计算复杂性。我认为在这种情况下,每次调用都会更加优化,因为如果将它们放入数组中(这是赋值操作+查找空的操作),那么当您得到完整的表时,您将调用函数insert的节点,该节点最终将与第一个选项中的函数相同,但具有大的for循环“内核”绝对不是
    typedef struct Data {
        int *myArray;             // the array where all integers are stored
        size_t size;              // the number of int that can be stored
        size_t firstAvailablePos; // the first free position of myArray
    } Data;
    
    /* reallocating the array with a simple exponential growth */
    int insertNode(Data *data, int newNum) {
        if (data->firstAvailablePos == data->size) {
            size_t newSize = (data->size < 32) ? 32 : data->size + data->size / 2;
            int *array = realloc(myArray, newSize * sizeof(*array));
            if (array == NULL)
                return -1;
            data->myArray = array;
            data->size = newSize;
        }
        data->myArray[data->firstAvailablePos++] = newNum;
        return 0;
    }
    
    int alt_insertNode(Data *data, int *array, size_t arraySize) {
        if (data->firstAvailablePos + arraySize > data->size) {
            size_t newSize = (data->size < 32) ? 32 : data->size + data->size / 2;
            while (newSize < data->firstAvailablePos + arraySize) {
                newSize += newSize / 2;
            }
            int *array = realloc(myArray, newSize * sizeof(*array));
            if (array == NULL)
                return -1;
            data->myArray = array;
            data->size = newSize;
        }
        memcpy(data->myArray + data->firstAvailablePos, array, arraySize * sizeof(*array));
        data->firstAvailablePos += arraySize;
        return 0;
    }