问题描述
Windows XP SP3.酷睿 2 双核 2.0 GHz.我发现 boost::lexical_cast 性能非常慢.想找出加快代码速度的方法.在 Visual c++ 2008 上使用/O2 优化并与 java 1.6 和 python 2.6.2 进行比较,我看到以下结果.
Windows XP SP3. Core 2 Duo 2.0 GHz.I'm finding the boost::lexical_cast performance to be extremely slow. Wanted to find out ways to speed up the code. Using /O2 optimizations on visual c++ 2008 and comparing with java 1.6 and python 2.6.2 I see the following results.
整数转换:
c++:
std::string s ;
for(int i = 0; i < 10000000; ++i)
{
s = boost::lexical_cast<string>(i);
}
java:
String s = new String();
for(int i = 0; i < 10000000; ++i)
{
s = new Integer(i).toString();
}
python:
for i in xrange(1,10000000):
s = str(i)
我看到的时间是
c++:6700 毫秒
c++: 6700 milliseconds
java:1178 毫秒
java: 1178 milliseconds
蟒蛇:6702 毫秒
c++ 和 python 一样慢,比 java 慢 6 倍.
c++ is as slow as python and 6 times slower than java.
双重转换:
c++:
std::string s ;
for(int i = 0; i < 10000000; ++i)
{
s = boost::lexical_cast<string>(d);
}
java:
String s = new String();
for(int i = 0; i < 10000000; ++i)
{
double d = i*1.0;
s = new Double(d).toString();
}
python:
for i in xrange(1,10000000):
d = i*1.0
s = str(d)
我看到的时代是
c++:56129 毫秒
c++: 56129 milliseconds
java:2852 毫秒
java: 2852 milliseconds
蟒蛇:30780 毫秒
python: 30780 milliseconds
所以对于 doubles,c++ 实际上是 python 速度的一半,比 java 解决方案慢 20 倍!!.关于提高 boost::lexical_cast 性能的任何想法?这是否源于糟糕的 stringstream 实现,或者我们是否可以期望使用 boost 库将性能普遍降低 10 倍.
So for doubles c++ is actually half the speed of python and 20 times slower than the java solution!!. Any ideas on improving the boost::lexical_cast performance? Does this stem from the poor stringstream implementation or can we expect a general 10x decrease in performance from using the boost libraries.
推荐答案
Edit 2012-04-11
rve 非常正确地评论了 lexical_cast 的性能,并提供了一个链接:
Edit 2012-04-11
rve quite rightly commented about lexical_cast's performance, providing a link:
http://www.boost.org/doc/libs/1_49_0/doc/html/boost_lexical_cast/performance.html
我现在无法提升 1.49,但我确实记得让我的代码在旧版本上更快.所以我猜:
I don't have access right now to boost 1.49, but I do remember making my code faster on an older version. So I guess:
- 以下答案仍然有效(如果仅用于学习目的)
- 可能在两个版本之间引入了优化(我会搜索)
- 这意味着 boost 仍然越来越好
原答案
只是添加有关 Barry's 和 Motti 出色答案的信息:
Original answer
Just to add info on Barry's and Motti's excellent answers:
请记住,Boost 是由这个星球上最优秀的 C++ 开发人员编写的,并由同样优秀的开发人员进行审核.如果 lexical_cast
是错误的,那么有人会通过批评或代码攻击该库.
Please remember Boost is written by the best C++ developers on this planet, and reviewed by the same best developers. If lexical_cast
was so wrong, someone would have hacked the library either with criticism or with code.
我猜你没注意到 lexical_cast
的真正价值...
I guess you missed the point of lexical_cast
's real value...
在 Java 中,您将整数转换为 Java 字符串.您会注意到我不是在谈论字符数组或用户定义的字符串.你也会注意到,我不是在谈论你的用户定义的整数.我说的是严格的 Java 整数和严格的 Java 字符串.
In Java, you are casting an integer into a Java String. You'll note I'm not talking about an array of characters, or a user defined string. You'll note, too, I'm not talking about your user-defined integer. I'm talking about strict Java Integer and strict Java String.
在 Python 中,您或多或少也在做同样的事情.
In Python, you are more or less doing the same.
正如其他帖子所说,本质上,您使用的是 sprintf
(或不太标准的 itoa
)的 Java 和 Python 等价物.
As said by other posts, you are, in essence, using the Java and Python equivalents of sprintf
(or the less standard itoa
).
在 C++ 中,您使用的是非常强大的强制转换.在原始速度性能方面并不强大(如果你想要速度,也许 sprintf
会更适合),但在可扩展性方面很强大.
In C++, you are using a very powerful cast. Not powerful in the sense of raw speed performance (if you want speed, perhaps sprintf
would be better suited), but powerful in the sense of extensibility.
如果您想比较 Java Integer.toString
方法,那么您应该将它与 C sprintf
或 C++ ostream
设施进行比较.
If you want to compare a Java Integer.toString
method, then you should compare it with either C sprintf
or C++ ostream
facilities.
C++ 流解决方案将比 lexical_cast
快 6 倍(在我的 g++ 上),并且可扩展性更差:
The C++ stream solution would be 6 times faster (on my g++) than lexical_cast
, and quite less extensible:
inline void toString(const int value, std::string & output)
{
// The largest 32-bit integer is 4294967295, that is 10 chars
// On the safe side, add 1 for sign, and 1 for trailing zero
char buffer[12] ;
sprintf(buffer, "%i", value) ;
output = buffer ;
}
C sprintf
解决方案将比 lexical_cast
快 8 倍(在我的 g++ 上),但安全性要低得多:
The C sprintf
solution would be 8 times faster (on my g++) than lexical_cast
but a lot less safe:
inline void toString(const int value, char * output)
{
sprintf(output, "%i", value) ;
}
这两种解决方案都与您的 Java 解决方案一样快或更快(根据您的数据).
Both solutions are either as fast or faster than your Java solution (according to your data).
如果你想比较一个 C++ lexical_cast
,那么你应该将它与这个 Java 伪代码进行比较:
If you want to compare a C++ lexical_cast
, then you should compare it with this Java pseudo code:
Source s ;
Target t = Target.fromString(Source(s).toString()) ;
Source 和 Target 可以是任何你想要的类型,包括像 boolean
或 int
这样的内置类型,这在 C++ 中是可能的,因为模板.
Source and Target being of whatever type you want, including built-in types like boolean
or int
, which is possible in C++ because of templates.
不,但它有一个众所周知的成本:当由同一位编码人员编写时,针对特定问题的通用解决方案通常比针对特定问题编写的特定解决方案慢.
No, but it has a well known cost: When written by the same coder, general solutions to specific problems are usually slower than specific solutions written for their specific problems.
在目前的情况下,在一个幼稚的观点中,lexical_cast
将使用流设施将 A
类型转换为字符串流,然后从这个字符串流转化为 B
类型.
In the current case, in a naive viewpoint, lexical_cast
will use the stream facilities to convert from a type A
into a string stream, and then from this string stream into a type B
.
这意味着只要您的对象可以输出到流中,并从流中输入,您就可以在其上使用 lexical_cast
,而无需触及任何一行代码.
This means that as long as your object can be output into a stream, and input from a stream, you'll be able to use lexical_cast
on it, without touching any single line of code.
词法转换的主要用途是:
The main uses of lexical casting are:
- 易于使用(嘿,C++ 类型转换,适用于所有值!)
- 将其与模板繁重的代码相结合,其中您的类型已参数化,因此您不想处理细节,也不想知道类型.
- 如果您有基本的模板知识,仍然可能相对高效,我将在下面演示
第 2 点在这里非常重要,因为这意味着我们只有一个接口/函数可以将一种类型的值转换为另一种类型的相等或相似的值.
The point 2 is very very important here, because it means we have one and only one interface/function to cast a value of a type into an equal or similar value of another type.
这是您错过的真正要点,也是性能方面的代价.
This is the real point you missed, and this is the point that costs in performance terms.
如果您想要原始速度性能,请记住您正在处理 C++,并且您有很多工具可以有效地处理转换,并且仍然保持 lexical_cast
易于使用的功能.
If you want raw speed performance, remember you're dealing with C++, and that you have a lot of facilities to handle conversion efficiently, and still, keep the lexical_cast
ease-of-use feature.
我花了几分钟查看 lexical_cast 源代码,并提出了一个可行的解决方案.将以下代码添加到您的 C++ 代码中:
It took me some minutes to look at the lexical_cast source, and come with a viable solution. Add to your C++ code the following code:
#ifdef SPECIALIZE_BOOST_LEXICAL_CAST_FOR_STRING_AND_INT
namespace boost
{
template<>
std::string lexical_cast<std::string, int>(const int &arg)
{
// The largest 32-bit integer is 4294967295, that is 10 chars
// On the safe side, add 1 for sign, and 1 for trailing zero
char buffer[12] ;
sprintf(buffer, "%i", arg) ;
return buffer ;
}
}
#endif
通过为字符串和整数启用 lexical_cast 的这种特殊化(通过定义宏 SPECIALIZE_BOOST_LEXICAL_CAST_FOR_STRING_AND_INT
),我的代码在我的 g++ 编译器上运行速度提高了 5 倍,这意味着,根据您的数据,它的性能应该类似于 Java 的.
By enabling this specialization of lexical_cast for strings and ints (by defining the macro SPECIALIZE_BOOST_LEXICAL_CAST_FOR_STRING_AND_INT
), my code went 5 time faster on my g++ compiler, which means, according to your data, its performance should be similar to Java's.
我花了 10 分钟查看 boost 代码,并编写了一个远程高效且正确的 32 位版本.通过一些工作,它可能会变得更快、更安全(例如,如果我们可以直接写入 std::string
内部缓冲区,我们可以避免使用临时外部缓冲区).
And it took me 10 minutes of looking at boost code, and write a remotely efficient and correct 32-bit version. And with some work, it could probably go faster and safer (if we had direct write access to the std::string
internal buffer, we could avoid a temporary external buffer, for example).
这篇关于boost::lexical_cast 性能很差的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!