奇怪的慢方法
Bizarrely slow method
我在我的项目中有一个方法,当放入自己的程序只需几秒钟即可运行,当在项目内部运行时,它属于它需要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项目时,它的速度与"慢"版本完全相同。情况下解决。使用较小的文件进行调试构建。
以下是一些我认为可以减缓启动过程的方法:
-
水平: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()
-
Level::CullInvalidNodes():对于std::vectors,使用remove-erase习语使擦除元素更快。您还需要重新考虑这个函数应该如何工作,因为它似乎有很多冗余的擦除和添加节点。在代码中,可以简单地将删除后的push_back()值赋给要删除的值,而不是擦除,这有意义吗?所以你可以简单地做
*itr = new_element;
,而不是v.erase(itr)
和v.push_back(new_element)
?免责声明:我还没有看到实际的函数做什么。说实话,我没时间管这个。我只是给你指出一种可能性。 在水平: : 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的数据文件的每行。当然会很慢。我想说这是故意的。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 没有为自己的结构调用列表推回方法
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在类定义之后定义一个私有方法
- 枚举环境变量的惯用C++14/C++17方法
- 初始化具有非默认构造函数的std::数组项的更好方法