奇怪的慢方法

时间:2011-11-14 10:53:00

标签: c++

我的项目中有一个方法,当放入自己的程序时只需几秒钟就可以运行,当它在项目所属的项目中运行时需要5分钟。我不知道为什么。我尝试过分析,取出比特,改变这一点。我很难过。

它填充了另一个类使用的整数向量,但此类当前未被实例化。我尽可能多地检查,看起来确实没有其他事情发生,但是这个方法在一个项目中神奇地花费的时间比在另一个项目中花费的时间长。

该方法在启动时运行,大约需要5分钟,如果单独运行则需要大约3秒钟。可能是什么导致了这个?奇怪的项目设置?多线程的东西,我不知道? (据我所知,除非自动完成,否则我的项目中没有任何内容)。

项目here有一个链接。如果有人能为我解决这个问题,我将非常感激,并且我能尽快为此开始赏金。

该方法称为PopulatePathVectors,在Level.cpp中运行。注释掉对方法的调用(在关卡构造函数中)意味着程序在几秒钟内启动。使用它生成的列表的唯一其他类是代理,但目前没有实例化。

编辑 - 根据要求,这是代码。虽然请记住我的问题不是'为什么代码慢?'但是“为什么它在一个地方很快而且在我的项目中很慢?”

//parses the text path vector into the engine
void Level::PopulatePathVectors(string pathTable)
{
    // Read the file line by line.
    ifstream myFile(pathTable);

        for (unsigned int i = 0; i < nodes.size(); i++)
        {
            pathLookupVectors.push_back(vector<vector<int>>());

            for (unsigned int j = 0; j < nodes.size(); j++)
            {
                string line;

                if (getline(myFile, line)) //enter if a line is read successfully
                {
                    stringstream ss(line);
                    istream_iterator<int> begin(ss), end;
                    pathLookupVectors[i].push_back(vector<int>(begin, end));
                }
            }
        }
}

编辑 - 我知道代码不是最好的,但这不是重点。它可以自行运行 - 大约3秒钟,这对我来说很好。我想解决的问题是为什么在项目中需要这么长时间。

编辑 - 除了主游戏循环之外,我评论了所有游戏代码。我将该方法放入代码的初始化部分,该部分在启动时运行一次。除了设置一个窗口的几个方法之外,它现在与只有方法的程序几乎相同,只有它仍然需要大约5分钟才能运行。现在我知道它与pathLookupVectors的依赖关系无关。此外,我知道这不是计算机开始写入硬盘驱动器的内存,因为当慢速程序正在运行该方法时,我可以打开另一个VS实例并同时运行单个方法程序秒。我意识到问题可能是一些基本的设置,但我没有经历过这样的道歉,如果这确实令人失望地成为原因。我仍然不知道为什么花了这么长时间。

如果在调试模式下不花这么长时间会很棒,因为这意味着每次我做出更改都要等待5分钟。这里必须有这么慢的原因。这些是减少项目中的其他标题:

#include <d3d10.h>
#include <d3dx10.h>
#include "direct3D.h"
#include "game.h"
#include "Mesh.h"
#include "Camera.h"
#include "Level.h"

#include <vector>

using namespace std;

编辑 - this是一个小得多的自包含项目,只有一小部分代码可以解决问题。

this也是一个非常小的项目,具有相同的代码,运行速度非常快。

3 个答案:

答案 0 :(得分:6)

我在MSVC10(您正在使用的编译器)中运行此代码,并使用您提供的项目复制结果。但是由于使用了快速版本,我无法使用此编译器进行配置。

我在MSVC9编译器中运行了这段代码,运行速度提高了5倍!我也描述了它,并得到了这些结果:

Initialize (97.43%)
    std::vector::_Assign (29.82%) 
        std::vector::erase (12.86%)
            std::vector::_Make_iter (3.71%)
            std::_Vector_const_iterator (3.14%)
        std::_Iterator_base (3.71%)
        std::~_Ranit (3.64%)
    std::getline (27.74%)
        std::basic_string::append (12.16%)
            std::basic_string::_Grow (3.66%)
            std::basic_string::_Eos (3.43%)
        std::basic_streambuf::snextc (5.61%)
    std::operator<<(std::string) (13.04%)
        std::basic_streambuf::sputc(5.84%)
    std::vector::push_back (11.84%)
        std::_Uninit_move::?? (3.32%)
    std::basic_istream::operator>>(int) (7.77%)
        std::num_get::get (4.6%)
            std::num_get::do_get (4.55%)

“快速”版本获得了以下结果:(缩放以匹配其他时间):

Initialize (97.42%)
    std::_Uninit_copy (31.72%)
        std::_Construct (18.58%)
        std::_Vector_const_iterator::operator++ (6.34%)
        std::_Vector_const_iterator::operator!= (3.62%)
    std::getline (25.37%)
        std::getline (13.14%)
        std::basic_ios::widen (12.23%)
    std::_Construct (18.58%)
        std::vector::vector (14.05%)
    std::_Destroy (14.95%)
        std::vector::~vector (11.33%)
    std::vector::_Tidy (23.46%)
        std::_Destroy (19.89%)
            std::vector::~vector (12.23%)
        [ntdll.dll] (3.62%)

在研究了这些结果并多次考虑Michael Price的评论之后,我突然意识到确保输入文件的大小相同。当我意识到这一点时,我意识到“快速”版本的配置文件,显示std::operator<<(std::string)std::vector::push_back,这看起来很可疑。我检查了MethodTest项目,发现它没有WepTestLevelPathTable.txt,导致getline失败,整个函数几乎什么都没做,除了分配一堆空向量。当我将WepTestLevelPathTable.txt复制到MethodTest项目时,它与“慢”版本的速度完全相同。案件解决了。使用较小的文件进行调试构建。

答案 1 :(得分:2)

以下是我认为可能会减慢启动过程的一些方法:

  1. 等级:: GenerateGridNodes():

    void Level::GenerateGridNodes()
    {
        int gridHeight = gridSize;
        int gridWidth = gridSize;
    
        // ADD THIS STATEMENT:
        nodes.reserve(gridHeight*gridWidth);
    
        for (int h = 2; h <= gridHeight; h++)
        {
            for (int w = 2; w <= gridWidth; w++)
            {
                nodes.push_back(Node(D3DXVECTOR3((float)w, (float)h, 0)));
            }
        }
    }//end GenerateGridNodes()
    
  2. Level :: CullInvalidNodes():对于std :: vectors,使用remove-erase idiom可以更快地删除元素。您还需要重新考虑此函数应该如何工作,因为它似乎有大量的还原剂擦除和添加节点。在代码中是否有意义而不是擦除你可以简单地将删除后的push_back()值分配给你正在擦除的值?那么,v.erase(itr)代替v.push_back(new_element),而不是*itr = new_element;,你可以简单地void Level::LinkNodes() { //generates a vector for every node // ADD THIS BEFORE THE FOR LOOP nodeAdjacencyVectors.reserve(nodes.size()); for (unsigned int i = 0; ....) //... Rest of the code }//end LinkNodes() 吗? 免责声明:我实际上没有看到这些功能的作用。老实说,我没有时间。我只是指出你的可能性。

  3. 在Level :: LinkNodes()中:

    {{1}}
  4. 简而言之,您仍有很大的改进空间。我相信主要的是Level类功能。您应该仔细研究它,并可能重新思考每个函数应该如何实现。特别是在Level类的构造函数中调用的那些。

答案 2 :(得分:0)

它在循环中包含一个循环,每个内循环读取超过30 MB的数据文件的每一行。当然它会很慢。我会说它的设计很慢。