2015-07-02 58 views
0

我只是不明白我做错了什么。下面显示的unicode tokenizer函数非常慢。也许有人可以给我一个提示如何加快速度? 感谢您的帮助。顺便说一句,ustringGlib::ustringsep1是隔板,不应该在结果 sep2是隔板应该是单一令牌在结果C++ - Tokenizer非常慢

void tokenize(const ustring & u, const ustring & sep1, 
     const ustring & sep2, vector<ustring> & tokens) { 
    ustring s; 
    s.reserve(100); 
    ostringstream os; 
    gunichar c; 
    for (int i = 0; i < u.length(); i++) { 
     c = u[i]; 
     if (sep1.find(c) != ustring::npos) { 
      tokens.push_back(s); 
      s = ""; 
     } 
     else if (sep2.find(c) != ustring::npos) { 
      tokens.push_back(s); 
      s = ""; 
      s.append(1, c); 
      tokens.push_back(s); 
      s = ""; 
     } 
     else { 
      s.append(1, c); 
     } 
    } 
    if (s!="") 
    tokens.push_back(s); 
} 

我现在它改变到(现在的1之间和2秒)显示:

ustring s; 
s.reserve(100); 
ostringstream os; 
gunichar c; 

set<gunichar> set_sep1; 
int i=0; 

for (i=0;i<sep1.size();i++) 
{ 
    set_sep1.insert(sep1[i]); 
} 

set<gunichar> set_sep2; 
for (i=0;i<sep2.size();i++) 
{ 
    set_sep2.insert(sep2[i]); 
} 

int start_index=-1; 
int ulen=u.length(); 
i=0; 
for (ustring::const_iterator it=u.begin();it!=u.end();++it) 
{ 
    c=*it; 
    if (set_sep1.find(c)!=set_sep1.end()) 
    { 
     if (start_index!=-1 && start_index<i) 
      tokens.push_back(u.substr(start_index,i-start_index)); 
     start_index=i+1; 
     s=""; 
    } 
    else if (set_sep2.find(c)!=set_sep2.end()) 
    { 
     tokens.push_back(s); 
     s=""; 
     tokens.push_back(s); 
     start_index=i+1; 
     s=""; 
    } 
    i++; 
} 
if (start_index!=-1 && start_index<ulen) 
    tokens.push_back(u.substr(start_index,ulen-start_index)); 
+0

有一件事你可以做的是不使用频繁'.append()'调用,并开始使用索引。即将标记开始的索引存储在一个变量中,并且一旦遇到标记的结尾,就执行'tokens.push_back(u.substr(start,end - start))'。使用迭代器可能比这个方法更好... –

+0

你是否分析了你的代码?探查器在哪里找到瓶颈? –

回答

2

的事物,可能是 “非常非常慢” 这里是:通过operator[]

  1. ustring::length()
  2. ustring::append()
  3. 随机访问ustring:例如c=u[i];

尝试以下操作:

  1. 而是在循环中调用u.length()的,长度存储在一个变量,在环比较变量
  2. 追加当前令牌的字符一个ostringstreamwostringstream而不是一个ustring
  3. 迭代通过ustring使用迭代器,而不是索引涉及随机访问。

例子:

for(ustring::const_iterator it = u.cbegin(); it != u.cend(); it++) 
{ 
    c = *it; 
    //implementation follows 
} 
+0

非常好,非常感谢,运行时间从22秒减少到了1.67秒 –

+0

@TimvorderBrück,你是否用'wostringstream'替换了'ustring :: append',或者只是从随机访问更改为迭代?除非您正在处理内存中的千兆字节数或磁盘上的数百兆字节,否则在计算世界中1.67秒是很长时间的。 –

+0

看到我的修改程序 –

1

我认为下面的代码会大大加快你的代码,但是要找出一点点工作。目前你是:

  1. 遍历你的每个字符。
  2. 在sep1中查找该字符是否在分隔符中。
  3. 根据需要一次追加一个字符。

假设你的分隔符的列表比你解析字符串时,你可能会更好做了以下内容:

  1. 对于每一个分隔符,做一个查找,看是否分隔符是在字符串
  2. 如果找到,则一次追加整个子字符串,然后在剩余子字符串上查找。

第二个优化是按照最可能成功的方式对您的分隔符进行排序。如果用于例如“,”是最常用的分隔符,请确保该查找首先运行。如果一个分离器比其他分离器热得多,这将会产生很大的差异。