utf8 < - > utf16:codecvt性能不佳

Xtr*_*der 11 c++ performance utf-8 c++11

我正在研究一些旧的(并且专门针对win32)的东西,并考虑使它更现代/可移植 - 即在C++ 11中重新实现一些可广泛重用的部分.其中一个部分是在utf8和utf16之间进行转换.在Win32 API中,我正在使用MultiByteToWideChar/ WideCharToMultiByte,尝试使用此处的示例代码将这些内容移植到C++ 11:https://stackoverflow.com/a/14809553.结果是

发布版本(由MSVS 2013编译,在Core i7 3610QM上运行)

stdlib                   = 1587.2 ms
Win32                    =  127.2 ms
Run Code Online (Sandbox Code Playgroud)

调试构建

stdlib                   = 5733.8 ms
Win32                    =  127.2 ms
Run Code Online (Sandbox Code Playgroud)

问题是 - 代码有问题吗?如果一切似乎都没问题 - 这种性能差异是否有充分的理由?

测试代码如下:

#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <clocale>  
#include <codecvt> 

#define XU_BEGIN_TIMER(NAME)                       \
    {                                           \
        LARGE_INTEGER   __freq;                 \
        LARGE_INTEGER   __t0;                   \
        LARGE_INTEGER   __t1;                   \
        double          __tms;                  \
        const char*     __tname = NAME;         \
        char            __tbuf[0xff];           \
                                                \
        QueryPerformanceFrequency(&__freq);     \
        QueryPerformanceCounter(&__t0);         

#define XU_END_TIMER()                             \
        QueryPerformanceCounter(&__t1);         \
        __tms = (__t1.QuadPart - __t0.QuadPart) * 1000.0 / __freq.QuadPart; \
        sprintf_s(__tbuf, sizeof(__tbuf), "    %-24s = %6.1f ms\n", __tname, __tms ); \
        OutputDebugStringA(__tbuf);             \
        printf(__tbuf);                         \
    }   

std::string read_utf8() {
    std::ifstream infile("C:/temp/UTF-8-demo.txt");
    std::string fileData((std::istreambuf_iterator<char>(infile)),
                         std::istreambuf_iterator<char>());
    infile.close();

    return fileData;
}

void testMethod() {
    std::setlocale(LC_ALL, "en_US.UTF-8");
    std::string source = read_utf8();
    {
        std::string utf8;

        XU_BEGIN_TIMER("stdlib") {
            for( int i = 0; i < 1000; i++ ) {
                std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert2utf16;
                std::u16string utf16 = convert2utf16.from_bytes(source);

                std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert2utf8;
                utf8 = convert2utf8.to_bytes(utf16);
            }
        } XU_END_TIMER();

        FILE* output = fopen("c:\\temp\\utf8-std.dat", "wb");
        fwrite(utf8.c_str(), 1, utf8.length(), output);
        fclose(output);
    }

    char* utf8 = NULL;
    int cchA = 0;

    {
        XU_BEGIN_TIMER("Win32") {
            for( int i = 0; i < 1000; i++ ) {
                WCHAR* utf16 = new WCHAR[source.length() + 1];
                int cchW;
                utf8 = new char[source.length() + 1];

                cchW = MultiByteToWideChar(
                    CP_UTF8, 0, source.c_str(), source.length(),
                    utf16, source.length() + 1);

                cchA = WideCharToMultiByte(
                    CP_UTF8, 0, utf16, cchW,
                    utf8, source.length() + 1, NULL, false);

                delete[] utf16;
                if( i != 999 )
                    delete[] utf8;
            }
        } XU_END_TIMER();

        FILE* output = fopen("c:\\temp\\utf8-win.dat", "wb");
        fwrite(utf8, 1, cchA, output);
        fclose(output);

        delete[] utf8;
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 10

在我自己的测试中,我发现构造函数调用wstring_convert有一个巨大的开销,至少在Windows上.正如其他答案所示,您可能很难击败本机Windows实现,但尝试修改代码以在循环之外构建转换器.我希望你会看到5x到20x之间的改进,特别是在调试版本中.

  • std :: wstring_convert不是线程安全的。您可以使用thread_local而不是static。 (3认同)
  • 原来这正是我所面临的问题。使构造函数静态化:繁荣! (2认同)

Cor*_*son 5

自Vista以来,Win32的UTF8转码在内部使用SSE产生了很大的效果,而其他UTF转码器却很少这样做。我怀疑即使是最优化的可移植代码也无法击败。

但是,codecvt如果您花费的时间超过原来的10倍,那么您给出的这个数字将非常慢,并且建议您采用简单的方法。在编写自己的UTF-8解码器时,我的性能是Win32的2-3倍。这里有很多改进的余地,但是您需要自定义实现编解码器才能获得它。

  • 自Vista以来_Win32的UTF8转码,在内部使用SSE效果非常好..._-您有参考吗? (6认同)