我已经将这个简单的方法从C#转换为C++.它读取路径表并填充整数列表(或整数向量的向量).
路径表中的示例行类似于
0 12 5 16 n
Run Code Online (Sandbox Code Playgroud)
我知道有一般这样做的更好的办法,但现在我只想知道为什么我的C++代码正在采取这么多的时间.例如10分钟而不是C#版本的10秒钟.这是我的C++代码.我猜我做的事情有点严重错误.
//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));
}
}
}
myFile.close();
}
Run Code Online (Sandbox Code Playgroud)
这是C#版本:
private void PopulatePathLists(string pathList)
{
// Read the file and display it line by line.
StreamReader streamReader = new StreamReader(pathList);
for (int i = 0; i < nodes.Count; i++)
{
pathLookupLists.Add(new List<List<int>>());
for (int j = 0; j < nodes.Count; j++)
{
string str = streamReader.ReadLine();
pathLookupLists[i].Add(new List<int>());
//For every string (list of ints) - put each one into these lists
int count = 0;
string tempString = "";
while (str[count].ToString() != "n") //While character does not equal null terminator
{
if (str[count].ToString() == " ") //Character equals space, set the temp string
//as the node index, and move on
{
pathLookupLists[i][j].Add(Convert.ToInt32(tempString));
tempString = "";
}
else //If characters are adjacent, put them together
{
tempString = tempString + str[count];
}
count++;
}
}
}
streamReader.Close();
}
Run Code Online (Sandbox Code Playgroud)
对不起,这是如此具体,但我很难过.
编辑 - 很多人都说他们已经测试了这段代码,它们只需要几秒钟.我所知道的是,如果我注释掉对此函数的调用,程序会在几秒钟内加载.使用函数调用需要5分钟.几乎一模一样.我真的很难过.问题是什么?
这是它正在使用的PathTable.
编辑 - 我尝试在程序中自行运行该功能,并且花了几秒钟,但我担心我不知道如何解决这个问题.显然这不是代码.会是什么呢?我检查了它被调用的地方,看看是否有多个电话,但没有.它位于游戏关卡的构造函数中,只调用一次.
编辑 - 我知道代码不是最好的,但这不是重点.它可以自行运行 - 大约3秒钟,这对我来说很好.我试图解决的问题是为什么在项目中需要这么长时间.
编辑 - 除了主游戏循环之外,我评论了所有游戏代码.我将该方法放入代码的初始化部分,该部分在启动时运行一次.除了设置一个窗口的几个方法之外,它现在与只有方法的程序几乎相同,只有它仍然需要大约5分钟才能运行.现在我知道它与pathLookupVectors的依赖关系无关.此外,我知道这不是计算机开始写入硬盘驱动器的内存,因为当慢速程序正在运行该方法时,我可以打开另一个Visual Studio实例并在完成的同时运行单个方法程序很快.我意识到问题可能是一些基本的设置,但我没有经历过这样的道歉,如果这确实令人失望地成为原因.我仍然不知道为什么要花这么长时间.
我用Very Sleepy(Visual C++ 2010,32位Windows XP)分析了代码.我不知道我的输入数据有多相似,但无论如何这里都是结果:
39%的时间花在了basic_istream :: operator >>上
12%basic_iostream :: basic_iostream
9%的运营商+
8%_Mutex :: Mutex
5%的getline
5%basic_stringbuf :: _ Init
4%locale :: _ Locimp :: _ Addfac
4%vector :: reserve
4%basic_string :: assign
3%运营商删除
2%basic_Streambuf :: basic_streambuf
1%Wcsxfrm
5%其他功能
有些东西似乎来自内联调用,因此有点难以说出它实际来自哪里.但你仍然可以得到这个想法.这里应该做I/O的唯一事情是getline,只需要5%.其余的是流和字符串操作的开销.C++流很慢.
while代码中的循环看起来非常混乱和冗长,因为它以不需要的方式执行操作:
一个简单而快速的等效代码就是:
int result;
stringstream ss(line);
while ( ss >> result ) //reads all ints untill it encounters non-int
{
pathLookupVectors[i][j].push_back(result);
}
Run Code Online (Sandbox Code Playgroud)
在C++中,这样的循环也是惯用的.或者代替这个手动循环,您可以编写使用std::copy 1:
std::copy(std::istream_iterator<int>( ss ),
std::istream_iterator<int>(),
std::back_inserter(pathLookupVectors[i][j]));
Run Code Online (Sandbox Code Playgroud)
这取自@David的评论.
或者甚至更好,如果你这样做,当你push_back的矢量本身:
if (getline(myFile, line)) //enter if a line is read successfully
{
stringstream ss(line);
std::istream_iterator<int> begin(ss), end;
pathLookupVectors[i].push_back(vector<int>(begin, end));
}
Run Code Online (Sandbox Code Playgroud)
完成!
根据您的更新,很明显您自己发布的功能不会导致性能问题,因此虽然您可以通过多种方式对其进行优化,但似乎无济于事.
我认为每次运行代码都可以重现这个性能问题,对吗?然后我建议你做以下测试:
如果你是在调试模式下编译你的程序(即没有优化),那么重新编译发布(完全优化,有利于速度),看看是否有所作为.
要检查是否在此可疑函数上花费了额外时间,可以在函数的开头和结尾添加包含时间戳的printf语句.如果这不是一个控制台应用程序,但GUI应用程序和printfs不会去任何地方,那么写入日志文件.如果您使用的是Windows,则可以使用OutputDebugString并使用调试器捕获printfs.如果您使用的是Linux,则可以使用syslog写入系统日志.
使用源代码分析器确定所花费的时间.如果调用此函数与否之间的差异是几分钟,那么分析器肯定会给出发生了什么的线索.如果你在Windows上,那么Very Sleepy是一个不错的选择,如果你在Linux上,你可以使用OProfile.
更新:所以你说发布版本很快.这可能意味着您在此函数中使用的库函数具有较慢的调试实现.STL就是这样知道的.
我确定您需要调试应用程序的其他部分,并且您不希望等待所有这些时间才能在调试模式下完成此功能.此问题的解决方案是在发布模式下构建项目,但以下列方式更改发布配置:
仅对要调试的文件禁用优化(确保优化至少对具有慢速函数的文件保持启用状态).要禁用文件的优化,请在Solution Explorer中选择该文件,右键单击,选择Properties,然后转到Configuration Properties | C/C++/Optimization.查看该页面中的所有项目是如何为Debug构建设置的,并复制Release版本中的所有项目.对您希望调试器可用的所有文件重复此操作.
启用要生成的调试信息(pdb文件).为此,请选择Solution Explorer顶部的Project,右键单击,选择Properties.然后转到Configuration Properties | Linker | Debugging并将Debug构建中的所有设置复制到Release构建中.
通过上述更改,您将能够调试上面配置的发布二进制文件的部分,就像在调试版本中一样.
完成调试后,您需要重新设置所有这些设置.
我希望这有帮助.