奇怪的慢方法

Bizarrely slow method

本文关键字:方法      更新时间:2023-10-16

我在我的项目中有一个方法,当放入自己的程序只需几秒钟即可运行,当在项目内部运行时,它属于它需要5分钟。我不知道为什么。我试过侧写,去掉一些,改变这个和那个。我难住了。

填充一个由整数组成的向量供另一个类使用,但是这个类当前没有被实例化。我已经检查了尽可能多的我可以,它似乎真的没有什么发生,但方法神奇地在一个项目中比在另一个项目中花费更长的时间。

该方法在启动时运行,大约需要5分钟,如果单独运行大约需要3秒。是什么原因造成的呢?奇怪的项目设置?多线程的东西,我不知道?(据我所知,在我的项目中没有,除非它是自动完成的)。

这里有一个项目链接。如果有人能帮我解决这个问题,我将非常感激,一旦我能开始赏金。

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

EDIT -按要求,这里是代码。不过请记住,我的问题不是"为什么代码慢?"而是"为什么某个地方快,而我的项目却慢?"'

//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分钟,那就太好了。这里这么慢一定是有原因的。这些是cut - down项目中包含的其他头文件:

#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;

EDIT -这是一个更小的自包含项目,只有一小部分代码,问题仍然发生。

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

我在MSVC10(您正在使用的相同编译器)中运行此代码,并将结果与您提供的项目复制。然而,由于使用express版本,我无法使用此编译器进行配置。

我在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. 水平: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习语使擦除元素更快。您还需要重新考虑这个函数应该如何工作,因为它似乎有很多冗余的擦除和添加节点。在代码中,可以简单地将删除后的push_back()值赋给要删除的值,而不是擦除,这有意义吗?所以你可以简单地做*itr = new_element;,而不是v.erase(itr)v.push_back(new_element) ?免责声明:我还没有看到实际的函数做什么。说实话,我没时间管这个。我只是给你指出一种可能性。

  3. 在水平:
  4. : LinkNodes ():

    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()
    

简而言之,你还有很大的改进空间。我认为主要的问题是Level类函数。您应该再看一遍它,并可能重新考虑每个函数应该如何实现。特别是在Level类的构造函数中调用的那些。

它包含一个循环中的循环,每个内循环读取超过30MB的数据文件的每行。当然会很慢。我想说这是故意的。