C++/CLI. Тормозит конверсия String -> std::wstring
От: Codealot Земля  
Дата: 29.06.22 17:16
Оценка:
Есть массив String[], который конвертируется в vector<wstring> вот так:
    std::vector<std::wstring> buf(vals->Length);
    for (auto i = 0; i < vals->Length; i++)
    {
        auto ptr = Marshal::StringToHGlobalUni(vals[i]);
        auto pStr = (wchar_t*)(void*)ptr;
        std::wstring str(pStr);
        Marshal::FreeHGlobal(ptr);

        buf[i] = str;
    }

Проблема в том, что на тестовом массиве эта конверсия занимает 24 секунды, в то время как заполнение исходного String[] (в C# !!!) занимает всего 6 секунд.
Вопрос — в чем тут проблема?
Ад пуст, все бесы здесь.
Re: C++/CLI. Тормозит конверсия String -> std::wstring
От: kov_serg Россия  
Дата: 29.06.22 17:43
Оценка:
Здравствуйте, Codealot, Вы писали:

C>Проблема в том, что на тестовом массиве эта конверсия занимает 24 секунды, в то время как заполнение исходного String[] (в C# !!!) занимает всего 6 секунд.

И что вас смущает?
Re: C++/CLI. Тормозит конверсия String -> std::wstring
От: Вертер  
Дата: 29.06.22 18:23
Оценка: 4 (1)
Здравствуйте, Codealot, Вы писали:

C>
C>    buf[i] = std::move(str);
C>    // или
C>    std::swap(buf[i], str);
C>    // или
C>    buf[i].swap(str);
C>
Re: C++/CLI. Тормозит конверсия String -> std::wstring
От: Вертер  
Дата: 29.06.22 18:27
Оценка:
C>
C>    auto len = vals->Length;
C>    std::vector<std::wstring> buf(len);
C>    for (auto i = 0; i < len; i++)
C>    {
C>    }
C>
Re[2]: C++/CLI. Тормозит конверсия String -> std::wstring
От: Codealot Земля  
Дата: 29.06.22 18:56
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>И что вас смущает?


Нужно всего-то скопировать строку из одного блока памяти в другой, откуда такие бешеные затраты времени?
Ад пуст, все бесы здесь.
Re[2]: C++/CLI. Тормозит конверсия String -> std::wstring
От: Codealot Земля  
Дата: 29.06.22 18:56
Оценка:
Здравствуйте, Вертер, Вы писали:

Экономия на спичках.
Ад пуст, все бесы здесь.
Re[2]: C++/CLI. Тормозит конверсия String -> std::wstring
От: Codealot Земля  
Дата: 29.06.22 19:14
Оценка:
Здравствуйте, Вертер, Вы писали:

Немного быстрее, но ненамного. Оно разве не должно копировать содержимое строки в новый объект wstring как ссылку?
Ад пуст, все бесы здесь.
Re[3]: C++/CLI. Тормозит конверсия String -> std::wstring
От: Вертер  
Дата: 29.06.22 20:31
Оценка:
C>Немного быстрее, но ненамного. Оно разве не должно копировать содержимое строки в новый объект wstring как ссылку?

это вам не C#. Тут по умолчанию идёт копирование одной строки в другую.
Re: C++/CLI. Тормозит конверсия String -> std::wstring
От: pilgrim_ Россия  
Дата: 29.06.22 22:49
Оценка: 11 (2) +1
Здравствуйте, Codealot, Вы писали:

C>Есть массив String[], который конвертируется в vector<wstring> вот так:

C>
C>    std::vector<std::wstring> buf(vals->Length); //создание вектора на N элементов пустых и ненужных wstring
C>    for (auto i = 0; i < vals->Length; i++)
C>    {
C>        auto ptr = Marshal::StringToHGlobalUni(vals[i]); //1
C>        auto pStr = (wchar_t*)(void*)ptr;
C>        std::wstring str(pStr); //2
C>        Marshal::FreeHGlobal(ptr); 

C>        buf[i] = str; //3
C>    }
C>

C>Проблема в том, что на тестовом массиве эта конверсия занимает 24 секунды, в то время как заполнение исходного String[] (в C# !!!) занимает всего 6 секунд.
C>Вопрос — в чем тут проблема?

У тебя 3 аллокаций/копирования, вместо возможной одной.

Вариант с 1-й аллокацией/копированием:

std::vector<std::wstring> buf;
buf.reserve(vals->Length); //зарезервировали память для N элементов wstring
for (auto i = 0; i < vals->Length; i++)
{
    buf.push_back(std::move(msclr::interop::marshal_as<std::wstring>(vals[i])));
}


Немного более оптимальная и многословная версия, развёрнутый метод marshal_as и где объект wstring создаётся inplace в векторе:
std::vector<std::wstring> buf;
buf.reserve(vals->Length); //зарезервировали память для N элементов wstring
for (auto i = 0; i < vals->Length; i++)
{
    auto val = vals[i];
    cli::pin_ptr<const wchar_t> ptr = PtrToStringChars(val);
    buf.emplace_back(static_cast<const wchar_t *>(ptr), val->Length);
}



ps: и убедись что проверяешь релизную версию С++, т.к. в отладочной версии в std немалое количество всяких проверок.
Ну и как уже подсказали, если исходный managed массив строк сформирован на основе уже готовых строк, то в в .NET это по сути копирование указателя в массив, в варианте C++/wstring — это всегда аллокация/копирование.
pps: в современном C++ ещё есть string_view, и если строки в C++/Cli нужны на короткое время, то имеет смысл запинить их все и юзать string_view — 0 аллокаций и копирования.
Re[2]: C++/CLI. Тормозит конверсия String -> std::wstring
От: Codealot Земля  
Дата: 29.06.22 22:54
Оценка:
Здравствуйте, pilgrim_, Вы писали:

_>Немного более оптимальная и многословная версия, развёрнутый метод marshal_as и где объект wstring создаётся inplace в векторе:


А marshal_as категорически не хочет компилироваться.

_>ps: и убедись что проверяешь релизную версию С++, т.к. в отладочной версии в std немалое количество всяких проверок.


Ха. В дебаге всё еще в разы хуже.

_>Ну и как уже подсказали, если исходный managed массив строк сформирован на основе уже готовых строк, то в в .NET это по сути копирование указателя в массив, в варианте C++/wstring — это всегда аллокация/копирование.


Естественно. Но даже если полностью копировать строки, всё равно в разы быстрее.
Ад пуст, все бесы здесь.
Re[3]: C++/CLI. Тормозит конверсия String -> std::wstring
От: pilgrim_ Россия  
Дата: 29.06.22 22:59
Оценка:
Здравствуйте, Codealot, Вы писали:

C>Здравствуйте, pilgrim_, Вы писали:


_>>Немного более оптимальная и многословная версия, развёрнутый метод marshal_as и где объект wstring создаётся inplace в векторе:


C>А marshal_as категорически не хочет компилироваться.


Включи заголовочный файл: msclr\marshal_cppstd.h
Вариант без marshal_as: PtrToStringChars живёт в vcclr.h

ps: а какую версию VS/C++ используешь?
Отредактировано 29.06.2022 23:00 pilgrim_ . Предыдущая версия .
Re[4]: C++/CLI. Тормозит конверсия String -> std::wstring
От: Codealot Земля  
Дата: 30.06.22 00:23
Оценка:
Здравствуйте, pilgrim_, Вы писали:

_>Включи заголовочный файл: msclr\marshal_cppstd.h


Спасибо, Кэп.

Error C7681 two-phase name lookup is not supported for C++/CLI or C++/CX; use /Zc:twoPhase-



_>ps: а какую версию VS/C++ используешь?


2022
Ад пуст, все бесы здесь.
Re[5]: C++/CLI. Тормозит конверсия String -> std::wstring
От: pilgrim_ Россия  
Дата: 30.06.22 00:38
Оценка:
Здравствуйте, Codealot, Вы писали:

C>Здравствуйте, pilgrim_, Вы писали:


_>>Включи заголовочный файл: msclr\marshal_cppstd.h


C>Спасибо, Кэп.

C>

C>Error C7681 two-phase name lookup is not supported for C++/CLI or C++/CX; use /Zc:twoPhase-

C>

Ну борись с компилятором, в гугле должно быть решение

_>>ps: а какую версию VS/C++ используешь?


C>2022


В 2015/2017 работало норм.

ps: вариант без marshal_as не должен зависеть от этих косяков компилятора.
Re[3]: C++/CLI. Тормозит конверсия String -> std::wstring
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.06.22 11:54
Оценка:
Здравствуйте, Codealot, Вы писали:
C>Немного быстрее, но ненамного. Оно разве не должно копировать содержимое строки в новый объект wstring как ссылку?
Тогда бы у вас в результате операции FreeHGlobal объекты wstring указывали в космос.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: C++/CLI. Тормозит конверсия String -> std::wstring
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.06.22 11:57
Оценка:
Здравствуйте, Codealot, Вы писали:

C>Есть массив String[], который конвертируется в vector<wstring> вот так:

C>
C>    std::vector<std::wstring> buf(vals->Length);
C>    for (auto i = 0; i < vals->Length; i++)
C>    {
C>        auto ptr = Marshal::StringToHGlobalUni(vals[i]);
C>        auto pStr = (wchar_t*)(void*)ptr;
C>        std::wstring str(pStr);
C>        Marshal::FreeHGlobal(ptr);

C>        buf[i] = str;
C>    }
C>

C>Проблема в том, что на тестовом массиве эта конверсия занимает 24 секунды, в то время как заполнение исходного String[] (в C# !!!) занимает всего 6 секунд.
C>Вопрос — в чем тут проблема?
Навскидку — вы используете самый неудачный конструктор wstring, т.к. по документации он перед копированием вычисляет длину строки через length(). То есть сканирует строку в поисках \0.
Ну, не считая, конечно, адски медленного выделения и освобождения памяти в HGlobal.
Чем вас не устроил стандартный marshal_as? https://docs.microsoft.com/en-us/cpp/dotnet/overview-of-marshaling-in-cpp
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: C++/CLI. Тормозит конверсия String -> std::wstring
От: Sharowarsheg  
Дата: 30.06.22 12:01
Оценка: :)
Здравствуйте, Codealot, Вы писали:

C>Есть массив String[], который конвертируется в vector<wstring> вот так:

C>Проблема в том, что на тестовом массиве эта конверсия занимает 24 секунды, в то время как заполнение исходного String[] (в C# !!!) занимает всего 6 секунд.

Не то чтобы я могу что-то сказать по делу, но мне очень интересно — сколько там этих строк примерно, что шесть секунд нужно на преобразование?
Re[4]: C++/CLI. Тормозит конверсия String -> std::wstring
От: Codealot Земля  
Дата: 30.06.22 14:54
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Тогда бы у вас в результате операции FreeHGlobal объекты wstring указывали в космос.


Ты даже не понял, о чем речь
Ад пуст, все бесы здесь.
Re[2]: C++/CLI. Тормозит конверсия String -> std::wstring
От: Codealot Земля  
Дата: 30.06.22 14:54
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Ну, не считая, конечно, адски медленного выделения и освобождения памяти в HGlobal.


А почему не считая, собственно? И почему оно адски медленное?

S>Чем вас не устроил стандартный marshal_as? https://docs.microsoft.com/en-us/cpp/dotnet/overview-of-marshaling-in-cpp


Тем, что его хрен заставишь работать.
Ад пуст, все бесы здесь.
Re[6]: C++/CLI. Тормозит конверсия String -> std::wstring
От: Codealot Земля  
Дата: 30.06.22 14:54
Оценка:
Здравствуйте, pilgrim_, Вы писали:

_>Ну борись с компилятором, в гугле должно быть решение


Рабочего не нашел. Не то ломается, так это.

_>ps: вариант без marshal_as не должен зависеть от этих косяков компилятора.


Пока что единственный рабочий вариант, который мне удалось найти — это
pin_ptr<const wchar_t> pStr = PtrToStringChars(cur);
Ад пуст, все бесы здесь.
Re: C++/CLI. Тормозит конверсия String -> std::wstring
От: DiZSl  
Дата: 30.06.22 15:18
Оценка: :)
Здравствуйте, Codealot

ни разу не специалист по CLI, но маршалинг обычно подразумевает обращение через очередь сообщений.
Если при вызове функции используется честный маршалинг, то оно в принципе быстро работать не будет.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.