Bjarne Stroustrup和其他专家说,在Bjarne Stroustrup' article和my previous question
中处理短字符串时,C ++比C更快但在我的测试中,C++
比C
慢了约110%。
g ++版本是4.4.6(在CentOS 6.3上运行)。这是因为g ++ 4.4.6具有较少的c ++ 11功能,例如Rvalue Reference (move semantics)
?
测试结果
$ time a.out input_file
的输出减去无调用compose_X()
函数的执行时间
源代码
使用-O2
修改
compose_cpp()
和compose_p()
来自Bjarne的文章。他说compose_cpp()
比compose_p()
更早。我想用真实的测试来检查这个事实。
如果我测试错误,我该如何改进测试?
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
std::string compose_cpp(const std::string& name, const std::string& domain)
{
return name + '@' + domain;
}
char* compose_c(const char* name, const char* domain)
{
char* res = (char*) malloc(strlen(name)+strlen(domain)+2);
char* p = strcpy(res,name);
p += strlen(name);
*p = '@';
strcpy(p+1,domain);
return res;
}
int main(int argc, char* argv[])
{
std::ifstream ifs;
ifs.open(argv[1]);
std::string email, domain;
while (ifs.good())
{
ifs >> email;
ifs >> domain;
// std::string composed = compose_cpp(email, domain);
char* composed = compose_c(email.c_str(), domain.c_str());
free(composed);
}
ifs.close();
}
输入文件
输入文件长度为1毫米。每行少于20个字节,随机生成。
$ head -n 10 input.txt.1m
9742720 1981857.com
22504 4127435.com
342760 69167.com
53075 26710.com
3837481 1851920.com
98441 278536.com
4503887 9588108.com
193947 90885.com
42603 8166125.com
3587671 297296.com
答案 0 :(得分:2)
我想在这里猜一下,因为我没有要测试的数据文件。我认为你的结果可能与Stroustrup的期望不符,因为他在这里说的话:
是的,C ++版本,因为它不必计算参数字符,也不使用免费存储(动态内存)作为短参数字符串。
但是,我的理解是libstdc++
对所有字符串使用动态内存(零长度字符串除外)。有关std::string
中libstdc++
对象的小尺寸问题,请参阅最近的回答:https://stackoverflow.com/a/27631366/12711
使用短字符串优化的实现(例如MSVC - 我不确定clang的libc ++是否使用它)可能会有更好的结果。
答案 1 :(得分:2)
我冒昧地将测试程序扩展了一点。特别是,我添加了代码,让它在内部生成数据,而不是依赖于外部文件,添加时序代码来隔离有问题的字符串处理,并让它在同一个运行中执行字符串操作的C ++和C版本,所以它立即产生了我可以比较的结果。这给了我以下代码:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <ctime>
char* compose_c(const char* name, const char* domain)
{
char* res = (char*) malloc(strlen(name)+strlen(domain)+2);
char* p = strcpy(res,name);
p += strlen(name);
*p = '@';
strcpy(p+1,domain);
return res;
}
std::string rand_string(int size){
std::string ret;
for (int i = 0; i < size; i++)
ret.push_back(rand() % 10 + '0');
return ret;
}
struct address {
std::string email, domain;
address() : email(rand_string(5)), domain(rand_string(4) + ".com") { }
};
struct composed {
std::string addr;
composed(address const &a) : addr(a.email + "@" + a.domain) {}
};
void report(clock_t d, std::string const &label){
std::cout << double(d) / CLOCKS_PER_SEC << " seconds for " << label << "\n";
}
int main(int argc, char **argv) {
static const int NUM = 1024 * 1024;
std::vector<address> addresses(NUM);
clock_t start = clock();
{
std::vector<composed> c{ addresses.begin(), addresses.end() };
}
report(clock() - start, "C++");
std::vector<char *> c_results(addresses.size());
clock_t start_c = clock();
for (int i = 0; i < addresses.size(); i++)
c_results[i] = compose_c(addresses[i].email.c_str(), addresses[i].domain.c_str());
for (char *c : c_results)
free(c);
report(clock() - start_c, "C");
}
然后我用VC ++ 2013,x64使用标志-O2b2 -GL -EHsc
编译了它。当我跑步时,我得到的结果是:
0.071 seconds for C++
0.12 seconds for C
虽然运行之间存在某些变体,但这些变量具有相当的代表性 - C代码几乎(但不完全)是C ++代码的两倍。
请注意,尽管事实上我实际上给了C版本一些不公平的优势。 C ++代码的时间不仅包括进行字符串操作的时间,还包括创建和销毁向量以保存结果的时间。对于C代码,我提前准备向量,然后仅代码来创建和销毁字符串本身。
为了确保这个结果不是侥幸,我也尝试改变一些自变量。例如,增加我们组成的地址字符串数量10倍会增加总时间,但对比率几乎没有影响:
0.714 seconds for C++
1.206 seconds for C
同样,更改顺序以便首先运行C代码,然后运行C ++代码没有明显的效果。
我想我应该添加:确实如此,这段代码实际上并没有像原作那样使用compose_cpp
函数,而是选择将功能合并到composed
的构造函数中。为了完整起见,我写了一个使用compose_cpp
的版本,如下所示:
std::vector<std::string> composed;
composed.reserve(NUM);
clock_t start = clock();
for (auto const &a : addresses)
composed.push_back(compose_cpp(a.email, a.domain));
这实际上稍微改善了时间,但是我猜它主要是 因为时间代码中移动创建向量本身的时间,并且不够大差异很在乎:
0.631 seconds for C++
1.21 seconds for C
这些结果在很大程度上依赖于标准库实现 - 特别是std::string
实现短字符串优化的事实。在相同的硬件上运行相同的代码,但使用缺少此优化的实现(在我的情况下,gcc 4.9.1的nuwen MinGW分布)给出相当不同的结果:
2.689 seconds for C++
1.131 seconds for C
在这种情况下,C代码比VC ++的代码快一点,但是C ++代码的速度减慢了大约4倍。我尝试了一些不同的编译器标志(-O2与-O3等)但它们只有很小的影响 - 对于这个测试,缺乏短串优化显然支配其他因素。
结论:我认为这证实了C ++代码可以比C代码快得多,但实现这一速度更多地取决于实现的质量。如果实现无法提供短字符串优化,则C ++代码可以轻松快2倍,而不是C版本的2倍。