C ++连接字符串的最快方法(最佳方式)

时间:2015-09-21 21:55:23

标签: c++ string performance concatenation

我正在创建一个必须提供非常大的报告的应用程序,并且我遇到过程中最慢的部分是它必须创建最终的JSON字符串,所以我尝试了不同的东西来加速它并看到这是最快的

我开始对字符串进行++=操作。 然后我使用char * buffer更改了所有INT并稍微改进了一点。 然后我尝试了一些更大胆的东西,它使用FLOAT并自己管理连接,甚至将我自己的char * itoa2(UINT num, char * str) { if (num == 0) { *str++ = '0'; return str; } // Process individual digits UCHAR nsiz = (UCHAR)log10(num) + 1; str += nsiz; while (num != 0) { *str-- = (num % 10) + '0'; num = num/10; } return str + nsiz + 1; } char * ftoa2(float num, char * str) { int intg = (UINT)num; int dec = (UINT)((num - intg) * 1000); // Process individual digits UCHAR nsiz = (UCHAR)log10(intg) + 1; str += nsiz - 1; if (dec > 0) { nsiz += (UCHAR)log10(dec) + 2; str += nsiz - 1; while (dec != 0) { *str-- = (dec % 10) + '0'; dec = dec / 10; } *str-- = '.'; } if (intg == 0) { *str-- = '0'; } else { while (intg != 0) { *str-- = (intg % 10) + '0'; intg = intg / 10; } } return str + nsiz + 1; } void Formatter::jsonFormat2() { char * result = new char[1024 * 1024 * 1024]; //TODO: Use small buffers instead of this char * pos; string tmp; pos = result; (*pos++) = '['; const char * key; int keyPos; const Reporter::Entry * entry; set<Field *, Field::cmpOrder> * grouped = params->getGrouped(); bool byDay, byMonth, byYear; time_t ts = 0; struct tm * lt; char type; FieldData::fieldVariant fkey(0, nullptr); FieldData::fieldVariant * fvar; byDay = params->getByDay(); byMonth = params->getByMonth(); byYear = params->getByYear(); for (auto& it : *report) { key = it.first; entry = it.second; keyPos = 0; (*pos++) = '{'; if (byDay || byMonth || byYear) { ts = *(time_t *)key; keyPos += sizeof(time_t); lt = gmtime(&ts); } if (byDay) { memcpy(pos, "\"day\":\"", 7); pos+=7; pos = itoa2(lt->tm_year + 1900, pos); (*pos++) = '-'; if (lt->tm_mon+1 < 10) (*pos++) = '0'; pos = itoa2(lt->tm_mon+1, pos); (*pos++) = '-'; if (lt->tm_mday < 10) (*pos++) = '0'; pos = itoa2(lt->tm_mday, pos); (*pos++) = '\"'; (*pos++) = ','; memcpy(pos, "\"wday\":\"", 8); pos+=8; memcpy(pos, &weekDayC[lt->tm_wday * 3], 3); pos+=3; (*pos++) = '\"'; (*pos++) = ','; } if (byMonth) { memcpy(pos, "\"month\":\"", 9); pos+=9; pos = itoa2(lt->tm_year + 1900, pos); (*pos++) = '-'; if (lt->tm_mon+1 < 10) (*pos++) = '0'; pos = itoa2(lt->tm_mon, pos); (*pos++) = '\"'; (*pos++) = ','; } if (byYear) { memcpy(pos, "\"year\":\"", 8); pos+=9; pos = itoa2(lt->tm_year + 1900, pos); (*pos++) = '\"'; (*pos++) = ','; } for (auto& field : *grouped) { (*pos++) = '\"'; tmp = field->getName(); memcpy(pos, tmp.c_str(), tmp.length()); pos+=tmp.length(); memcpy(pos, "\":\"", 3); pos+=3; type = field->getType(); if (type == INT8) { pos = itoa2(*(key + keyPos), pos); } else if (type == INT16) { pos = itoa2(*(USHORT *)(key + keyPos), pos); } else if (type == INT32) { pos = itoa2(*(UINT *)(key + keyPos), pos); } else if (type == INT64) { pos = itoa2(*(ULONG *)(key + keyPos), pos); } else if (type == INT128) { pos = itoa2(*(UXLONG *)(key + keyPos), pos); } else if (type == CHAR2) { memcpy(pos, key + keyPos, 2); pos+=2; } (*pos++) = '\"'; (*pos++) = ','; for (auto& fieldData : *field->getFieldData()) { fkey.type = field->getType(); if (fkey.type == CHAR2) { fkey.data = new string((char *) (key + keyPos), 2); } else fkey.data = (void *)key + keyPos; fvar = fieldData->find(&fkey); (*pos++) = '\"'; tmp = fieldData->colName; memcpy(pos, tmp.c_str(), tmp.length()); pos+=tmp.length(); memcpy(pos, "\":\"", 3); pos+=3; if (fvar != nullptr) tmp = toString(fvar); else tmp = "null"; memcpy(pos, tmp.c_str(), tmp.length()); pos+=tmp.length(); memcpy(pos, "\",", 2); pos+=2; } keyPos += field->getBytes(); } memcpy(pos, "\"imps\":\"", 8); pos+=8; pos = itoa2(entry->imps, pos); (*pos++) = '\"'; (*pos++) = ','; memcpy(pos, "\"impsn\":\"", 9); pos+=9; pos = itoa2(entry->impsn, pos); (*pos++) = '\"'; (*pos++) = ','; memcpy(pos, "\"impsu\":\"", 9); pos+=9; pos = itoa2(entry->impsu, pos); (*pos++) = '\"'; (*pos++) = ','; memcpy(pos, "\"clicks\":\"", 10); pos+=10; pos = itoa2(entry->clicks, pos); (*pos++) = '\"'; (*pos++) = ','; memcpy(pos, "\"clicksu\":\"", 11); pos+=11; pos = itoa2(entry->clicksu, pos); (*pos++) = '\"'; (*pos++) = ','; memcpy(pos, "\"revenue\":\"", 11); pos+=11; pos = ftoa2(entry->revenue, pos); (*pos++) = '\"'; (*pos++) = ','; memcpy(pos, "\"revenue_2\":\"", 13); pos+=13; pos = ftoa2(entry->revenue_2, pos); (*pos++) = '\"'; (*pos++) = ','; memcpy(pos, "\"revenue_3\":\"", 13); pos+=13; pos = ftoa2(entry->revenue_3, pos); (*pos++) = '\"'; (*pos++) = ','; memcpy(pos, "\"convs\":\"", 9); pos+=9; pos = itoa2(entry->convs, pos); (*pos++) = '\"'; (*pos++) = ','; memcpy(pos, "\"convs_2\":\"", 11); pos+=11; pos = itoa2(entry->convs_2, pos); (*pos++) = '\"'; (*pos++) = ','; memcpy(pos, "\"convs_3\":\"", 11); pos+=11; pos = itoa2(entry->convs_3, pos); (*pos++) = '\"'; (*pos++) = ','; (*pos++) = '}'; (*pos++) = ','; pos+=3; } pos--; (*pos++) = ']'; (*pos++) = '\0'; if (params->getVerbose()) cout << string(result, pos - result); } session[:user_id] = @user.id设置为字符串函数。 并且它将时间缩短了30%,但是对于大型报告,这个过程仍然需要大约15个segs,我希望将时间减少到最小,所以我会在这里粘贴我的代码,看看是否有任何改进性能的建议

class SessionsController < ApplicationController
  def new
  end

  def create
    @user = User.find_by_nom(params[:session][:NOM])
    if @user && @user.authenticate(params[:session][:password])
      session[:user_id] = @user.id
      redirect_to '/'
    else
      flash[:alert] = "Usuario o contraseña incorrectos"
      redirect_to '/login'
    end
    end

  def destroy
    session[:user_id] = nil
    redirect_to '/'
    end

end

1 个答案:

答案 0 :(得分:1)

在同一方法Formatter::jsonFormat2()中,您有

char * result = new char[1024 * 1024 * 1024];

位于顶部,

if (params->getVerbose()) cout << string(result, pos - result);

在底部。

这意味着,每次调用此方法时,您不仅会有1GB的内存泄漏,如果getVerbose()碰巧返回false,您也会做很多工作(您可以在开始时检查它) )。

此外,如果您 要将所有内容写入std::cout(或针对此问题的任何流),请考虑使用流插入语法直接编写各种片段({ {1}}运营商)。