C/C++&Java 字符串拼接效率对比(上部)[内容超过长度被截断完成可以下载文档和源码]
C/C++&Java字符串拼接效率对比
??? C/C++拼接字符串的方式很多,尤其是所谓的”VC++”语言(不应该称其为语言,但是很多使用VC++的程序员却把它变成了VC++语言即微软血统的C++语言)中这种方式又变多一些。在Windows下的Visual C++中很多的程序员习惯使用微软MFC中CString 。虽然使用MFC编程时使用CString来处理字符串的确有着与MFC库配合的便利。但是在开发中如果并没有用到MFC的时候我建议还使用 Standard C++的字符串。好处很多首先它是标准的意味着你使用它(std::string, std::wstring)来处理字符串。并且你的程序没有使用与具体操作系统相关的API (或使用了跨平台的相关类库代替)。 那么意味着你的代码在有对应平台的并且符合C++标准的编译器下可以直接编译通过。也意味着你的程序具备较好的跨平台能力。另外在性能方面也较为出色。下面测试了一下在VC++2008中各种字符串拼接方式的性能对比。当然这里面有有预分配方式的,测试程序中最后会根据每一项的耗时进行排序,当然排序的结果需要看是否采用预分配方式。当然C++ std::string, std::wstring中有一些提高效率的机制(在非预分配方式下)。然后又在Java中测试了一下字符Java的StringBuffer及StringBuilder字符串拼接效率也很不错。最后测试的结果有助于指导我们使用最高效的方式处理字符处拼接。
?
以下测试代码:
注:在 const int TEST_TIMES = 9000000;时C的memcpy使用16-32 ms(毫秒) std::string 也在 1000 ms(毫秒)左右。由于其他的方式耗时过长因此将 TEST_TIMES = 90000次在Java中普通的String也是如此.
#include "stdafx.h"
#include <string>
#include <sstream>
#include <iostream>
#include <cassert>
#include <cstring>
#include <ctime>
#include <vector>
#include <algorithm>
#include <afxwin.h>
?
using namespace std;
?
?
const int????? TEST_TIMES????????????? = 90000;
const char?? APPEND_CONTENT[]?????? = "cppmule";
const int????? PREALLOCATE_SIZE = strlen(APPEND_CONTENT) * TEST_TIMES+ 1;
?
class Statistic {
public:
?????? string item;
?????? int used;
?????? friend inline ostream & operator<< (ostream & os, const Statistic &stat){
????????????? os?? <<"item: " << stat.item<< endl
??????????????????????????? <<"used: " << stat.used<< " ms." << endl << endl;
????????????? return os;
?????? }
??????
?????? inline bool operator>(const Statistic& stat){
????????????? return (used > stat.used);
?????? }
?
?????? inline bool operator<(const Statistic& stat){
????????????? return (used < stat.used);
?????? }
};
?
vector<Statistic> g_statistics;
?
#define BEGIN_TICK() \
?????? clock_t start =clock();
?
#define END_AND_PRINT_TICK(info)????? \
?????? clock_t used = clock() - start;???? ?????? \
?????? Statistic stat;?????????????????? ????????????? \
?????? stat.item.assign(info);?????????? ?????? \
?????? stat.used = used;???????????? ????????????? \
?????? g_statistics.push_back(stat);????? ?????? \
?????? cout << info<< " Used: " << used << "ms." << endl;
?
#define PRINT_SORT_TEST_TICKS()?????? ???????????????????? \
?????? sort(g_statistics.begin(), g_statistics.end());?????? ?????? \
?????? struct StatisticPrinter{ ???????????????????? ?????? \
????????????? StatisticPrinter() : order(0) {}????????? ?????? \
????????????? void operator() (const Statistic&stat) {? ?????? \
???????????????????? ++order;????? ???????????????????? ?????? \
???????????????????? cout << "sortorder: " << order <<endl?? \
?????????????????????????????????? ?<< stat;????? ?????? ?????? \
????????????? }???? ?????????????????????????????????? ?????? \
????????????? int order;???? ??????????????????????????? ?????? \
?????? } printer;???? ????????????????????????????????????????? \
cout << "---------Statisticsinformations(sorting ascendent)-------" << endl << endl;???? \
?????? for_each(g_statistics.begin(), g_statistics.end(), printer);\
?????? cout << "----------------------"<< endl;
?
?
void test_stdstring_append()
{
?????? string str;
?????? BEGIN_TICK();
?????? for (int i=0; i<TEST_TIMES; i++){
????????????? str.append(APPEND_CONTENT);
?????? }
?????? END_AND_PRINT_TICK("std::stringappend");
?????? cout << "stringlength: " << str.length() << endl;
}
?
void test_stdstring_append_operator()
{
?????? string str;
?????? BEGIN_TICK();
?????? for (int i=0; i<TEST_TIMES; i++){
????????????? str += APPEND_CONTENT;
?????? }
?????? END_AND_PRINT_TICK("std::string+= operator");
?????? cout << "stringlength: " << str.length() << endl;
}
?
void test_stdostringstream()
{
?????? ostringstream oss;
?????? BEGIN_TICK();
?????? for (int i=0; i<TEST_TIMES; i++){
????????????? oss << APPEND_CONTENT;
?????? }
?????? END_AND_PRINT_TICK("std::ostringstream<<");
?????? cout << "stringlength: " << oss.str().length()<< endl;
}
?
void test_stdostringstream_preallocate()
{
?????? ostringstream oss;
?????? BEGIN_TICK();
?????? for (int i=0; i<TEST_TIMES; i++){
????????????? oss << APPEND_CONTENT;
?????? }
?????? END_AND_PRINT_TICK("std::ostringstream<<");
?????? cout << "stringlength: " << oss.str().length()<< endl;
}
?
void test_stdstring_append_operator_preallocate()
{
?????? string str;
?????? str.reserve(PREALLOCATE_SIZE);
?????? cout << "capacity:" << str.capacity() << endl
????????????? << "size: " << str.size()<< endl;
?????? //assert(str.capacity() == 1024*1024*512);
?????? BEGIN_TICK();
?????? for (int i=0; i<TEST_TIMES; i++){
????????????? str += APPEND_CONTENT;
?????? }
?????? END_AND_PRINT_TICK("havaresize(PREALLOCATE_SIZE) std::string += operator");
?????? cout << "stringlength: " << str.length() << endl;
}
?
void test_c_strcat_append()
{
?????? char* pstr = (char*)malloc(PREALLOCATE_SIZE);
?????? memset(pstr, 0,sizeof(pstr));
?
?????? BEGIN_TICK();
?????? for (int i=0; i<TEST_TIMES; i++){
????????????? strcat(pstr, APPEND_CONTENT);
?????? }
?????? END_AND_PRINT_TICK("cstring function strcat:");
?????? cout << "stringlength: " << strlen(pstr) << endl;
?
?????? free(pstr);
?????? pstr = NULL;
}
?
void test_c_memcpy_append()
{
?????? //Allocate memory
?????? char* pstr = (char*)malloc(PREALLOCATE_SIZE);
?????? if (NULL == pstr) {
????????????? cerr << "Can'tallocate memory." << endl;
????????????? return;
?????? }
?????? memset(pstr, 0,PREALLOCATE_SIZE);
?
?????? BEGIN_TICK();
?????? int len = 0;
?????? for (int i=0; i<TEST_TIMES; i++){
????????????? memcpy(pstr + len, APPEND_CONTENT,strlen(APPEND_CONTENT));
????????????? len += strlen(APPEND_CONTENT);
?????? }
?????? END_AND_PRINT_TICK("Clanguage memcpy append");
?????? cout << "stringlength: " << strlen(pstr) << endl;
?
?????? //Cleanup
?????? free(pstr);
?????? pstr = NULL;
}
?
void test_mfc_cstring_append()
{
?????? CString str;
?
?????? BEGIN_TICK();
?????? for (int i=0; i<TEST_TIMES; i++){
????????????? str.Append(APPEND_CONTENT);
?????? }
?????? END_AND_PRINT_TICK("MFCCString append");
?????? cout << "stringlength: " << str.GetLength() << endl;
}
?
void test_mfc_cstring_append_operator()
{
?????? CString str;
??????
?????? BEGIN_TICK();
?????? for (int i=0; i<TEST_TIMES; i++){
????????????? str += APPEND_CONTENT;
?????? }
?????? END_AND_PRINT_TICK("MFCCString operator append");
?????? cout << "stringlength: " << str.GetLength() << endl;
}
?
int _tmain(int argc, _TCHAR* argv[])
{
#ifdef _DEBUG
?????? cout<< "DEBUG version." << endl;
#else
?????? cout << "Releaseversion." << endl;
#endif
?????? cout << "TEST_TIME:" << TEST_TIMES << endl;
?
?????? test_c_memcpy_append();
?????? test_stdstring_append_operator();
?????? test_stdstring_append();
?????? test_stdostringstream();
?????? test_stdstring_append_operator_preallocate();
?????? test_mfc_cstring_append();
?????? test_mfc_cstring_append_operator();
?????? test_c_strcat_append();
?????? PRINT_SORT_TEST_TICKS();
??????
?????? return 0;
}
?请接下部。。。
//这句是为了清楚当前的环境对下面的测试的影响,保留只是为了使测试更加的准确
str=null;System.gc();
//StringBuffer
start = System.nanoTime();
//构造函数中的参数如果等于整个结果的长度,那么速度将达到最快!
StringBuffer strBuffer = new StringBuffer( TEST_TIMES*7 );
for (int i=0; i<TEST_TIMES; i++){strBuffer.append("cppmule");}
long strBufferUsed = System.nanoTime() - start;
System.out.println("StringBuffer append: " + strBufferUsed/1000000f + " ms.");
//这句是为了清楚当前的环境对下面的测试的影响,保留只是为了使测试更加的准确
strBuffer.delete(0, strBuffer.length() );strBuffer = null;System.gc();
//StringBuilder
start = System.nanoTime();
StringBuilder strBuilder = new StringBuilder( TEST_TIMES*7 );
for (int i=0; i<TEST_TIMES; i++){strBuilder.append("cppmule");}
long strBuilderUsed = System.nanoTime() - start;
System.out.println("StringBuilder append: " + strBuilderUsed/1000000f + " ms.");
System.out.println("Times: " + TEST_TIMES);
}
public static void main(String[] args) {
testJavaStringPerformance2();
}
在java中,其实,还有更加快的字符串拼接方法:就是自己靠char[]来组装。StringBuidler的实现原理也就是这样实现的。