Повышение производительности преобразования System.String в std :: wstring? - PullRequest
1 голос
/ 05 марта 2011

В настоящее время я оцениваю использование ADO.NET для приложения C ++, которое в настоящее время использует обычный старый ADO. Учитывая, что мы переделываем все взаимодействие с базами данных, мы хотели бы определить, будет ли выгодным использование более современной и активно развивающейся технологии ADO.NET.

После некоторых измерений выясняется, что для определенных тестовых запросов, которые извлекают много строк с несколькими столбцами, которые все содержат строки, ADO.NET фактически на 20% медленнее для нас, чем обычный ADO. Наш профилировщик предполагает, что преобразование результатов System.String в std :: wstring, используемое приложением, является одним из узких мест. Я не могу переключить ни один из верхних уровней приложения на использование System.String, поэтому мы застряли с этим конкретным преобразованием.

Грубый набросок кода выглядит так:

System::Data::SqlClient::SqlCommand^ sqlCmd =
  gcnew System::Data::SqlClient::SqlCommand(cmd, m_DBConnection.get());
System::Data::SqlClient::SqlDataReader^ reader = sqlCmd->ExecuteReader();
if (reader->HasRows)
{
    using namespace msclr::interop;
    while (reader->Read())
    {
      std::vector<std::wstring> results;
      for (int i=0; i < reader->FieldCount; ++i)
      {
        std::wstring col_data;
        TypeCode type = Type::GetTypeCode(reader->GetFieldType(i));
        switch (type)
        {
           // ... omit lots of different types
        case TypeCode::String:
          {
            System::String^ tmp = reader->GetString(i);
            col_data = marshal_as<std::wstring>(tmp);
          }
          break;
          // ... more type conversion code removed
        }
        results.push_back(col_data);
      }
      // NOTE: Callback into native result processing code
      ResultsCallback(results);
    }

Я потратил много времени на чтение различных способов получения std::wstring из System.String и измерил большинство из них. Кажется, что все они работают примерно одинаково - мы говорим о десятичных точках в процентах загрузки процессора. В конце концов, я просто согласился использовать marshal_as<std::wstring>, так как он наиболее читабелен и, по-видимому, так же эффективен, как и другие решения (то есть, используя PtrToStringChars или метод, описанный в MSDN здесь ).

Использование DataReader работает очень хорошо с концептуальной точки зрения, так как большая часть обработки данных в любом случае ориентирована на строки.

Единственное другое немного неожиданное узкое место, которое я заметил, - это получение TypeCode для столбцов результатов; Я уже планирую переместить это за пределы основного цикла обработки результатов и получать коды типов только один раз для каждого результата запроса.

После этого длительного введения кто-нибудь может порекомендовать менее дорогой способ преобразования строковых данных из System.String в std::wstring или я уже смотрю на оптимальную производительность здесь? Я, очевидно, больше ищу немного необычных способов, учитывая, что я уже попробовал все обычные ...

РЕДАКТИРОВАТЬ : Похоже, я попал в ловушку моего собственного изготовления здесь. Да, приведенный выше код примерно на 20% медленнее, чем эквивалентный простой код ADO в режиме Debug . Однако, переключая его в режим Release , узкое место все еще можно измерить, но приведенный выше код ADO.NET внезапно почти на 50% быстрее, чем старый код ADO. Так что, хотя меня все еще немного беспокоит стоимость преобразования строк, в режиме Release она не так велика, как это впервые показалось.

1 Ответ

0 голосов
/ 05 марта 2011

Я не вижу никакого способа оптимизировать это, поскольку реализация marshal_as<std::wstring> просто захватывает внутреннюю строку C и присваивает ее std::wstring.Вы не можете добиться гораздо большей эффективности, чем это.

Единственное решение, которое я вижу, - это разделение ваших строк и параллельная обработка потоков N .Единственная проблема заключается в том, что вам нужно зарезервировать достаточно места в вашем vector, чтобы предотвратить изменение размера во время обработки, но это выглядит достаточно просто.

Если вы используете Visual Studio 2010, я думаю,библиотеки потоков C ++ 0x было бы достаточно для этой задачи, хотя я не уверен, насколько (если она есть) реализована в Visual Studio до сих пор.

...