两个代码段之间执行时间的奇怪差异
Weird difference in execution time between two code segments
所以我想看看在比较之前不将变量的值复制到另一个变量中,可以在多大程度上提高程序的性能(这将在示例中得到更好的解释),我注意到了一些奇怪的事情。我有这两个代码段:
string a = "";
for (int i = 0; i < 1000000; i++) a += 'a';
for (int i = 0; i < 1000000; i++) {
if ('b' == a.at(i));//compare the two chars directly
}
和
string a = "";
for (int i = 0; i < 100000000; i++) a += 'a';
for (int i = 0; i < 100000000; i++) {
char c = a.at(i);//declare a new variable
if ('b' == c);//compare the char with the newly created variable,
//instead of comparing it to the other char directly
}
我认为第二个段的执行时间会更长,因为与第一个段相比,声明的变量多了一个。当我真正计时两个时,我发现第二个比第一个花的时间更短。我对它进行了几次计时,第二次执行的时间似乎总是少0.13秒左右。这是完整的代码:
#include <string>
#include <iostream>
#include <ctime>
using namespace std;
int main() {
clock_t timer;
string a = "";
string b;
for (int i = 0; i < 100000000; i++)
a += "a";
timer = clock();
for (int i = 0; i < 100000000; i++) {
if ('b'==a.at(i)) b += "a";
}
cout << (clock()-timer)/(float)CLOCKS_PER_SEC << "sec" << endl;
timer = clock();
for (int i = 0; i < 100000000; i++) {
char c = a.at(i);
if ('b'==c) b += "a";
}
cout << (clock()-timer)/(float)CLOCKS_PER_SEC << "sec" << endl;
return 0;
}
为什么会发生这种情况?
编辑:我遵循了NathanOliver的建议,为每个循环添加了单独的字符串,所以现在代码看起来是这样的:
#include <string>
#include <iostream>
#include <ctime>
using namespace std;
int main() {
clock_t timer;
string compare_string_1 = "";
string compare_string_2 = "";
string segment_1 = "";
string segment_2 = "";
for (int i = 0; i < 100000000; i++)
compare_string_1 += "a";
for (int i = 0; i < 100000000; i++)
compare_string_2 += "a";
timer = clock();
for (int i = 0; i < 100000000; i++) {
if ('b'==compare_string_1.at(i)) segment_1 += "a";
}
cout << (clock()-timer)/(float)CLOCKS_PER_SEC << "sec" << endl;
timer = clock();
for (int i = 0; i < 100000000; i++) {
char c = compare_string_2.at(i);
if ('b'==c) segment_2 += "a";
}
cout << (clock()-timer)/(float)CLOCKS_PER_SEC << "sec" << endl;
return 0;
}
使用Visual C++2010,我得到了与上面评论中相同的计时结果——平均而言,第二个循环占用的运行时间约为第一个循环的80%。有一两次,第一个循环有点快,但这可能是由于操作系统中的一些线程问题。检查拆卸结果如下:
第一个循环:
01231120 cmp dword ptr [ebp-38h],esi
01231123 jbe main+1CBh (123120Bh)
01231129 cmp dword ptr [ebp-34h],10h
0123112D mov eax,dword ptr [ebp-48h]
01231130 jae main+0F5h (1231135h)
01231132 lea eax,[ebp-48h]
01231135 cmp byte ptr [eax+esi],62h
01231139 jne main+108h (1231148h)
0123113B mov ebx,1
01231140 lea eax,[ebp-80h]
01231143 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::append (1231250h)
01231148 inc esi
01231149 cmp esi,5F5E100h
0123114F jl main+0E0h (1231120h)
第二个循环:
01231155 cmp dword ptr [ebp-1Ch],esi
01231158 jbe main+1CBh (123120Bh)
0123115E cmp dword ptr [ebp-18h],10h
01231162 mov eax,dword ptr [ebp-2Ch]
01231165 jae main+12Ah (123116Ah)
01231167 lea eax,[ebp-2Ch]
0123116A cmp byte ptr [eax+esi],62h
0123116E jne main+13Dh (123117Dh)
01231170 mov ebx,1
01231175 lea eax,[ebp-64h]
01231178 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::append (1231250h)
0123117D inc esi
0123117E cmp esi,5F5E100h
01231184 jl main+115h (1231155h)
由于生成的程序集看起来或多或少相同,我考虑了操作系统或CPU中的节流机制,你猜怎么着?添加睡眠(5000)导致第二个循环(几乎)总是比第一个循环慢。运行20次,第二个循环平均占用第一个循环运行时间的150%左右。
编辑:将自旋数增加五倍会得到相同的结果。我认为大约0.5秒的运行时间或多或少是可以可靠测量的。:-)
我认为,在原始代码中,操作系统可能需要几个时间片来检测CPU负载,然后在调度期间开始赋予线程更多的优先级,而且CPU可能会在一段时间后提升,使第一个循环的部分"未提升"。当第二个循环开始执行时,OS/CPU可能会为繁重的工作负载做好准备,并执行得更快。MMU或操作系统内部内存页面处理也可能发生同样的情况。当在循环之间添加Sleep时,可能会发生相反的情况,导致操作系统将线程搁置一段时间,直到最终检测到新的工作负载,从而使第二个循环的执行速度稍慢。
你的结果是什么?有没有人手头有像英特尔放大器这样的合适的分析器来测量CPI率和CPU速度在循环中的步进?
- 我可以创建一个包含两个变量的 for 循环,但时间复杂度仍然为 O(n) 吗?
- 如何检查两个 std::向量在小于 O(n) 的时间复杂度内是否相等
- 如何在两个 boost::multi_arrays (C++) 之间执行数学运算?
- 计算两个代码块的时间复杂度
- 如何使用发送数据包所花费的时间计算两个节点之间的距离?
- Levenshtein 两个文件的距离花费了太多时间
- 以天C++为单位的两个时间戳之间的差异
- 按 Tab 单步执行两个控制组
- 如何找到两个日期之间的时间差异(以秒和纳秒为单位)?
- 为什么循环体中的一个基本算术运算执行得比两个算术运算慢
- 为什么具有静态存储持续时间的同一内联变量在包含在 VS2017 编译的两个翻译单元中时会构造和销毁两次
- 与操作员比较两个计时时间点
- 如何获取两个时间点之间的时间
- 图问题:找出两个节点是否在每个节点的O(1)时间和O(2)存储中共享同一分支
- 两个嵌套循环的运行时间复杂性:二次型还是线性
- 使计时器在C++进程中的特定时间关闭,以便同步两个进程
- 给定的两个代码有什么区别.一个在 ideone 上运行时超出时间限制,另一个工作正常
- 如何比较两个经过的时间?
- 两个代码段之间执行时间的奇怪差异
- 套接字调用在同时执行的两个或多个线程上提供重复的文件描述符(竞争条件)