The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
Отказаться от UTF-8, !*! Sergey Maslennikov, 06-Авг-17, 16:51  [смотреть все]
Было бы логично для хранения русских текстов использовать двуязычную кодировку, и только предполагая ( > 2 )-язычность, -- UTF.  А существует ли это или обратное утверждение (UTF в любом случае) в строгом, т. е., доказанном виде?

Логичность утверждения можно было бы показать предположив, что хранимые тексты время от времени обрабатывают программами, которые распаковывают их, конвертируют во что-то равнодлинное на символ, что-то с этим делают, конвертируют в исходную кодировку и запаковывают. Времена конвертаций, распаковок и запаковок в случае хранения в UTF-8 больше, чем при хранении, скажем, в KOI8-R.

Если 300 "Анн Карениных" в одном файле (АК) конвертировать iconv из исходной кодировки в UTF-32 и обратно, то в случае исходной кодировки UTF-8 эта операция занимает в 1.3 раза больше времени, чем в случае исходной кодировки KOI8-R.

Если, 200 АК сжимать xz и разжимать обратно, то в случае кодировки UTF-8 эта операция занимает в 2 раза больше времени, чем в случае исходной кодировки KOI8-R.

300 АК и 200 АК -- чтобы время теста было порядка нескольких минут.

Всё это верно для моего лаптопа, конечно, но может оказаться, что и многие другие компьютеры покажут примерно такой же результат -- для UTF-8 операции паковки и конвертации окажутся энергозатратнее, чем для двуязычных кодировок. Или наоборот. Возможен ли строгий ответ?

  • Отказаться от UTF-8, !*! ыы, 02:19 , 07-Авг-17 (1) –1
    • Отказаться от UTF-8, !*! Sergey Maslennikov, 07:50 , 07-Авг-17 (2) +2
      > ... условие (распаковка) - надуманно

      А понимаешь, если не паковать, то ответ тривиален. В случае русского языка UTF-8 уступает вдвое любой распространённой двуязычной кодировке по занимаемому месту на диске и энергозатратам на копирование и передачу. Ты можешь почитать об этом, например, в Википедии [1] или здесь же [2].

      Причина в том, что в распакованном виде в UTF-8 русским буквам отведены 2-байтные коды в отличие от английских и большей части букв западноевропейских языков, которые записывают 1-байтными кодами.

      [1] https://en.wikipedia.org/wiki/UTF-8#Comparison_with_single-b...
      [2] https://www.opennet.ru/openforum/vsluhforumID1/51935.html

      • Отказаться от UTF-8, !*! eRIC, 08:49 , 07-Авг-17 (3) +1
        • Отказаться от UTF-8, !*! Sergey Maslennikov, 18:17 , 07-Авг-17 (13) +1
          > в чем проблема, если знаете

          Не помогает :(

          > под Unicode кодировку выделяются 2 байта и более ...

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

      • Отказаться от UTF-8, !*! ПавелС, 10:25 , 07-Авг-17 (4)
        • Отказаться от UTF-8, !*! Andrey Mitrofanov, 13:21 , 07-Авг-17 (6) +1
        • Отказаться от UTF-8, !*! Sergey Maslennikov, 17:15 , 07-Авг-17 (9) +1
          > в любом регионе мира. В случае например с koi8-r это уже
          > будет затруднительно.

          Ну, мы им инструкцию в регион зашлём. На utf-8 напишем, чтоб поняли уже наконец проблему нашу.

          • Отказаться от UTF-8, !*! Andrey Mitrofanov, 17:36 , 07-Авг-17 (10) +1
            • Отказаться от UTF-8, !*! Sergey Maslennikov, 17:43 , 07-Авг-17 (11)
              > байтики, два или полтора

              300 АК не хотите? Исходное сообщение читали?

              • Отказаться от UTF-8, !*! Andrey Mitrofanov, 19:08 , 07-Авг-17 (15) +1
                • Отказаться от UTF-8, !*! Sergey Maslennikov, 12:51 , 09-Авг-17 (52) +1
                  > Этих разнообразных архиваторов -- десятки.

                  xz был у меня на лаптопе.

                  > И _даже_ ключами xz можно весьма разные результаты получать -- сравните на
                  > своих карениных xz -1, -3, 5, -5, -1e, -3e, -9e по
                  > времени и сжатию.

                  Ну, я внёс свои две копейки. Могу ещё добавить, что распространённая программка sort сортирует UTF-8 в 1.7 раза медленнее, чем KOI8-R. Другие тоже могли бы что-то в этом направлении сделать, если нужным сочтут.

        • Отказаться от UTF-8, !*! Sergey Maslennikov, 08:40 , 08-Авг-17 (20) +1
          > при наличии шрифтов правильно отобразиться в любом регионе мира.

          Согласен с вами. Кириллический текст UTF-8 не отобразится, если в шрифте кириллицы нет. А если есть, то упомянутая вами KOI8-R отобразится быстрее, чем UTF-8, т. к. программа, которая будет отображать, тексты любых исходных кодировок сначала конвертирует в тексты унифицированной кодировки, с которыми потом и будет что-то делать -- отображать, например. Обычно это -- 4-байтная Unicode -- что-то типа UTF-32 (хороша тем, что длина кода не меняется от алфавита к алфавиту). Всё это, однако, нужно доказать.

          У меня есть _подозрение_ (не доказательство и даже не утверждение), что конвертация в унифицированное представление и обратно в среднем происходит быстрее, если исходная кодировка однобайтовая (упомянутая вами KOI8-R, например). Подозрение основано на том, что популярные программы из популярного дистрибутива Debian на моём лаптопе конвертируют KOI8-R -> UTF-32 -> KOI8-R быстрее, чем UTF-8 -> UTF-32 -> UTF-8. Основание слабовато, поэтому исходный пост -- это конкретный вопрос (можно ли доказать хотя бы это?), а не то, на что здесь пока пытаются отвечать.

          • Отказаться от UTF-8, !*! ыы, 09:49 , 08-Авг-17 (21)
            • Отказаться от UTF-8, !*! Sergey Maslennikov, 10:30 , 08-Авг-17 (22)
              > Вы в пятом или четвертом классе учитесь?

              А что, если бы я в четвёртом классе учился, вы не стали бы со мной разговаривать?

              Вот недавно физтеховские школьники выиграли международную олимпиаду по физике -- каждый взял высшую медаль. Смогли бы вы обыграть этих "детишек" в решении задач, а пусть даже, по программированию?

              > Вот вам строгое доказательство

              И вот смотрите. utf-8, вообще говоря, кодировка переменной длины. Вероятно, алгоритм, который разбирает текст в ней, не знает какой длины придёт к нему следующий код. Где это в вашем "доказательстве"?

              > Вы этого хотели?

              Не совсем.

      • Отказаться от UTF-8, !*! ыы, 13:05 , 07-Авг-17 (5)
        • Отказаться от UTF-8, !*! Sergey Maslennikov, 17:50 , 07-Авг-17 (12) +1
          > UTF-8 придумана не для того чтобы обеспечить максимально быстрое
          > исполнение или минимальный размер файлов.

          А что, люди ни этого ли хотят?

          На размер запакованного файла выбор кодировки влияет слабо, а максимально быстрой, предположительно, окажется обработка английского текста. Получается, что если сидеть на одной лишь UTF-8, то для английского языка оптимальная кодировка существует, а для русского -- нет.

          > Вы смотрите только на одну сторону большой комплексной проблемы.

          А больше пока некуда смотреть. Если окажется, что в тестах UTF-8 не уступает 1-байтным кодировкам, или это можно доказать, то и проблемы нет. Тогда только UTF-8.

          Или, о какой проблеме вы пишете?

          • Отказаться от UTF-8, !*! ыы, 19:12 , 07-Авг-17 (16) –1
          • Отказаться от UTF-8, !*! Andrey Mitrofanov, 19:14 , 07-Авг-17 (17)
            • Отказаться от UTF-8, !*! Sergey Maslennikov, 12:30 , 09-Авг-17 (49) +1
              > "Оптимальная" по каким параметрам?? ??"Желаю, чтобы всем!"(ц)ШариковПП

              По времени обработки.

              • Отказаться от UTF-8, !*! Andrey Mitrofanov, 12:46 , 09-Авг-17 (50)
                • Отказаться от UTF-8, !*! Sergey Maslennikov, 13:06 , 09-Авг-17 (55) +1
                  > Посмотрите memcpy().

                  А зачем? -- она не имеет отношения к разбору текста, только куски целиком копирует. И в какое её место смотреть?

                • Отказаться от UTF-8: memcpy(), !*! Sergey Maslennikov, 17:04 , 23-Авг-17 (95) +2
                  > Посмотрите memcpy().

                  Неправильно я ответил. Смысл посмотреть на memcpy() есть, если предположить, что кто-то решился бы копировать внутри программ однобайтно-кодированную кириллицу. В этом случае копирование произошло бы примерно в 1.75 раза быстрее, чем копирование того же текста в UTF-8 [1].

                  Функция memcpy() может быть по разному реализована, но в реализациях, которые я видел, ожидаемое время копирования должно быть пропорционально размеру копируемых данных. В UTF-8 текст в 1.75 раза длиннее, чем в KOI8-R -- вот и копирует memcpy() его во столько же раз дольше. Это же соотношение можно получить экспериментально [2].

                  Возможно, я не уловил суть или цель совета использовать memcpy() при оптимизации путём выбора кодировки.

                  Ссылки / сноски:
                  [1] -- если копировать тот же текст, что упомянут в исходном посте;
                  [2] Экспериментальная программка -- обёртка, которую я собираюсь изредка применять для тестирования функций ICU. Здесь в качестве примера тестируемой функции я вставил memcpy():

                  #include <stdio.h>
                  #include <stdlib.h>
                  #include <time.h>
                  #include <string.h>
                  #include <unicode/utypes.h>
                  #include <unicode/ucnv.h>

                  long delta_t(struct timespec *start, struct timespec *end)
                  {
                      time_t sec; long nsec;
                      if ((end->tv_nsec-start->tv_nsec)<0) {
                          sec = end->tv_sec-start->tv_sec-1;
                          nsec = 1000000000+end->tv_nsec-start->tv_nsec;
                      } else {
                          sec = end->tv_sec-start->tv_sec;
                          nsec = end->tv_nsec-start->tv_nsec;
                      }
                      return sec * 1000000000l + nsec;
                  }

                  int main()
                  {
                    const char fnm_initial[] = "../../anna-karenina";
                    FILE *fini = fopen(fnm_initial, "r");
                    if (fini == NULL) {
                      fprintf(stderr, "Can't open initial file.\n");
                      return -1;
                    }
                    fseek(fini, 0L, SEEK_END);
                    unsigned long len = ftell(fini), size = len + 1ul;
                    fseek(fini, 0L, SEEK_SET);
                    printf("Allocate %lu bytes to copy file \"%s\" ... ", size, fnm_initial); fflush(stdout);
                    char *text_koi8 = malloc(size);
                    if (text_koi8 == NULL) {
                      fclose(fini);
                      fprintf(stderr, "Can't allocate memory for \"text_koi8\".\n");
                      return -2;
                    }
                    printf("Done.\n"); fflush(stdout); /* Allocated */
                    if(fread(text_koi8, 1ul, len, fini) != len) {
                      free(text_koi8);
                      fclose(fini);
                      fprintf(stderr, "Can't read file \"%s\" into the buffer.\n", fnm_initial);
                      return -3;
                    }
                    fclose(fini);
                    text_koi8[len] = '\x0';
                    UErrorCode uerr = U_ZERO_ERROR;
                    /* Here it is the example of the UTF-8 buffer exact size evaluation. It is however faster
                       to allocate 2 * len + 1ul long buffer instaed and shrink it, after converting,
                       by realloc() to the value returned by ucnv_convert(). */
                    unsigned long size_u8 = ucnv_convert("UTF-8", "KOI8-R", NULL, 0ul, text_koi8, size, &uerr);
                    if( uerr != U_BUFFER_OVERFLOW_ERROR &&
                        uerr != U_STRING_NOT_TERMINATED_WARNING &&
                        U_FAILURE(uerr) ) {
                      free(text_koi8);
                      fclose(fini);
                      fprintf(stderr, "Can't evaluate UTF-8 text buffer size.\n");
                      return -4;
                    }
                    printf("UTF-8 text buffer size = %lu bytes.\n", size_u8);
                    char *text_utf8 = malloc(size_u8);
                    if( text_koi8 == NULL ) {
                      free(text_koi8);
                      fclose(fini);
                      fprintf(stderr, "Can't allocate memory for text_utf8.\n");
                      return -5;
                    }
                    uerr = U_ZERO_ERROR;
                    ucnv_convert("UTF-8", "KOI8-R", text_utf8, size_u8, text_koi8, size, &uerr);
                    if( U_FAILURE(uerr) ) {
                      free(text_utf8); free(text_koi8);
                      fclose(fini);
                      fprintf(stderr, "Error converting KOI8-R text into UTF-8 text.\n");
                      return -6;
                    }
                    /* At this point we have two buffers with the same text in koi8-r and utf-8. */
                    /* Prepare for measurements */
                    char *text_koi8_a = malloc(size);
                    if( text_koi8_a == NULL ) {
                      free(text_utf8); free(text_koi8); fclose(fini);
                      fprintf(stderr, " Can't allocate memory for \"text_koi8_a\".\n");
                      return -7;
                    }
                    char *text_utf8_a = malloc(size_u8);
                    if( text_utf8_a == NULL ) {
                      free(text_koi8_a); free(text_utf8); free(text_koi8); fclose(fini);
                      fprintf(stderr, "Can't allocate memory for \"text_utf8_a\".\n");
                      return -8;
                    }
                    /* Buffers to copy into are ready here. */
                    unsigned long i;
                    struct timespec t0, t1;
                    long Dt_call, Dt_koi8, Dt_utf8,
                         Dt_koi8_total = 0ul, Dt_utf8_total = 0ul;
                    double Dt_utf8_to_Dt_koi8;
                    for(i = 0; i < 220ul; i++) {
                      printf("------------- i = %lu -------------\n", i);
                      /* Estimation of time for the function call itself (with copying
                         negligibly small amount of data -- 1 byte) */
                      clock_gettime(CLOCK_MONOTONIC, &t0);
                      memcpy(text_koi8_a, text_koi8, 1ul);
                      clock_gettime(CLOCK_MONOTONIC, &t1);
                      Dt_call = delta_t(&t0, &t1); /* (in nanoseconds) */
                      printf("Dt_call = %ld ns\n", Dt_call);
                      /* Test for koi8-r */
                      clock_gettime(CLOCK_MONOTONIC, &t0);
                      memcpy(text_koi8_a, text_koi8, size);
                      clock_gettime(CLOCK_MONOTONIC, &t1);
                      Dt_koi8 = delta_t(&t0, &t1) - Dt_call;
                      printf("Dt_koi8 = %ld ns\n", Dt_koi8); fflush(stdout);
                      /* Test for utf-8 */
                      clock_gettime(CLOCK_MONOTONIC, &t0);
                      memcpy(text_utf8_a, text_utf8, size_u8);
                      clock_gettime(CLOCK_MONOTONIC, &t1);
                      Dt_utf8 = delta_t(&t0, &t1) - Dt_call;
                      if (i > 9ul) { /* Skip first 10 experiments (wait for stabilization) */
                        Dt_koi8_total += Dt_koi8;
                        Dt_utf8_total += Dt_utf8;
                      }
                      printf("Dt_utf8 = %ld ns\n", Dt_utf8);
                      Dt_utf8_to_Dt_koi8 = (double)Dt_utf8 / (double)Dt_koi8;
                      printf("Dt_utf8 / Dt_koi8 = %.5g\n", Dt_utf8_to_Dt_koi8);
                      fflush(stdout);
                    }
                    puts("===================================");
                    printf("Dt_koi8_total = %ld ns\nDt_utf8_total = %ld ns\n"
                           "Dt_utf8_total / Dt_koi8_total = %.5g\n",
                           Dt_koi8_total, Dt_utf8_total,
                           (double)Dt_utf8_total / (double)Dt_koi8_total);
                    printf("len_u8 / len = %.5g\n", (double)(size_u8 - 1ul) / (double)len );
                    free(text_utf8_a);
                    free(text_koi8_a);
                    free(text_utf8);
                    free(text_koi8);
                    return 0;
                  }

  • Отказаться от UTF-8, !*! XAnder, 19:05 , 07-Авг-17 (14)
  • Отказаться от UTF-8, !*! Led, 23:34 , 07-Авг-17 (18)
    • Отказаться от UTF-8, !*! Sergey Maslennikov, 08:19 , 08-Авг-17 (19) +1
      > А у тебя точно все-все французские символы (которые Лев Николаевич впендюрил в
      > эту книженцию) в твоёй кои8 правльно сохранились? А в "Войне и
      > мире"?

      АК был с Мошковской библиотеки. Там с текстом всё нормально -- французских букв нет.  Вот так там, например, в Войне и мире: "Еh bien, mon prince. G#234;nes et Lucques ne sont plus que des apanages, des поместья, de la famille Buonaparte.  Non, je  vous pr#233;viens..."

      В целом же, да, вкрапления английских букв и всяких "nbsp;" в тестах нежелательны, т. к. они уменьшают время обработки UTF-8, изменяя результат в её пользу. Т. е., в тестах на кириллице без вкраплений проигрыш UTF-8 оказался бы больше.

      Переделывать я всё равно не буду. Правильный тест должен проверять алгоритм, а не собранную программу. Пусть эти тесты сделает тот, кто в этом шарит и мог бы провести их минимальными усилиями. В идеале -- докажет:
      существует оптимальный алгоритм преобр. <1-байтная кодировка> -> <универсальное 4-байтное представление> и обратно; существует оптимальный алгоритм преобр. <UTF-8> -> <универсальное 4-байтное представление> и обратно; сравнит их сложности. Ну, или, хотя бы, экспериментальную базу увеличит.

  • Отказаться от UTF-8, !*! DeadLoco, 04:37 , 10-Авг-17 (57)
    • Отказаться от UTF-8: геморрой, !*! Sergey Maslennikov, 17:31 , 23-Авг-17 (96) +2
      > Геморрой, связанный с зоопарком ... В данном конкретном случае повышенный расход
      > дискового пространства, траффика и тактов процессора - это сознательная и приемлемая
      > плата за унификацию хранения текстов.

      Ну, вы уж слишком категоричны. Тред, всё-таки, в теме "Оптимизация и тюнинг", т. е. для тех, кому геморрой не "зоопарк", а "повышенный расход". В исходном сообщении не было никакого "данного конкретного случая". Речь не о полном отказе от UTF-8, а о принятии решения -- в каких случаях стоило бы посмотреть в сторону однобайтной кодировки. Понятно, что большинство программистов не будет заморачиваться поддержкой кучи кодировок внутри своих программ, но кто-то из них мог бы согласиться вставить опциональные конвертеры на входе и выходе. Без конвертеров тоже: если программа берёт на вход и выводит текст в UTF-8, вполне могут найтись люди, которые допишут к ней внешние паковщики с конвертерами прямо на своих системах (не геморрой же!), потому что паковать непосредственно UTF-8 системам сложнее. В частности, распаковка кириллического текста в KOI8-R с последующей конвертацией в UTF-8 (+ в обратном порядке) происходит в 1.6 раза быстрее, чем просто распаковка/запаковка того же текста в UTF-8 [1]. И не так уж это очевидно. По крайней мере, я раньше предполагал обратное. А с UTF-8, да, всё хорошо, если только она использована не для кириллицы.

      С другой стороны, геморрой -- это тоже экспериментальный факт. Народ считает, что геморрой, значит так оно и есть.

      Сноска:
      [1] Сжатие -- xz без опций, конвертация -- iconv, текст -- в основном кириллица; если время загрузки процессов много меньше времени их работы.




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру