boost::tokenizer 与 boost::split

新手上路,请多包涵

我正在尝试将每个 ‘^’ 字符上的 c++ 字符串解析为向量标记。我一直使用 boost::split 方法,但我现在正在编写性能关键代码,想知道哪一个能提供更好的性能。

例如:

 string message = "A^B^C^D";
vector<string> tokens;
boost::split(tokens, message, boost::is_any_of("^"));

对比

boost::char_separator<char> sep("^");
boost::tokenizer<boost::char_separator<char> > tokens(text, sep);

哪一个会提供更好的性能,为什么?

原文由 czchlong 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 575
2 个回答

最佳选择取决于几个因素。如果您只需要扫描一次令牌,那么 boost::tokenizer 在运行时和空间性能方面都是一个不错的选择(这些令牌向量可能会占用大量空间,具体取决于输入数据。)

如果您要经常扫描令牌,或者需要一个具有高效随机访问的向量,那么将 boost::split 转换为向量可能是更好的选择。

例如,在令牌长度为 1 字节的“A^B^C^…^Z”输入字符串中, boost::split/vector<string> 方法将消耗 至少 2*N-1 个字节。使用大多数 STL 实现中存储字符串的方式,您可以计算出它的数量是该数量的 8 倍以上。将这些字符串存储在向量中在内存和时间方面是昂贵的。

我在我的机器上进行了一次快速测试,具有 1000 万个令牌的类似模式如下所示:

  • boost::split = 2.5s~620MB
  • boost::tokenizer = 0.9s0MB

如果您只是对令牌进行一次性扫描,那么显然令牌生成器会更好。但是,如果您要分解成一个您希望在应用程序的生命周期内重用的结构,那么最好使用一个标记向量。

如果你想走矢量路线,那么我建议不要使用 vector<string> ,而是使用 string::iterators 的矢量。只需分解成一对迭代器并保留一大串令牌以供参考。例如:

 using namespace std;
vector<pair<string::const_iterator,string::const_iterator> > tokens;
boost::split(tokens, s, boost::is_any_of("^"));
for(auto beg=tokens.begin(); beg!=tokens.end();++beg){
   cout << string(beg->first,beg->second) << endl;
}

这个改进版本在同一台服务器上测试需要 1.6s390MB 。而且,最重要的是,这个向量的内存开销与令牌的数量成线性关系——不依赖于令牌的长度,而 std::vector<string> 存储每个令牌。

原文由 brandx 发布,翻译遵循 CC BY-SA 3.0 许可协议

要在其他答案中添加一些内容,请记住 split 不会标记 字符串,而 只是拆分它。这意味着如果您不小心传递给函数的输入,您可能会有不同的输出。

split(" stairway to heaven ") 将产生一个大小为 7 的向量。

tokenize(" stairway to heaven ") 将产生一个大小为 3 的向量。

原文由 Gerardo Zinno 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏