Добро пожаловать на Pro Pawn - Портал о PAWN-скриптинге.

Реклама



**Как получить V.I.P** (Перейти)
Чтобы заказать рекламу на Pro-Pawn.Ru, обращайтесь в Skype.
Баннерная реклама 100руб/мес, Текстовая 50руб/мес.
Показано с 1 по 1 из 1
  1. #1
    Аватар для Daniel_Cortez
    new fuck_logic[0] = EOS;

    Статус
    Оффлайн
    Регистрация
    06.04.2013
    Адрес
    Novokuznetsk, Russia
    Сообщений
    1,460
    Репутация:
    2021 ±

    Мифы о Pawn-скриптинге - #2

    Внимание: данная тема закрыта для защиты от копирования.
    Если есть какие-то вопросы, замечания или просто пожелания по поводу данного урока - оставляйте их здесь.


    Миф 2: "Если кода меньше, значит он лучше."

    Статус: Опровергнут.

    Описание:
    Чем-то похоже на предыдущий миф о якобы влиянии объёма исходного кода на оптимизацию, однако здесь имеется в виду сравнение не двух одинаковых кусков кода, один из которых "утрамбован" в одну строку, а просто разного кода.
    Например, некоторые "профессионалы" с govno-info твердят, что цикл for быстрее, чем while, или что "соединение" строк с помощью format происходит быстрее, чем с помощью strcat.

    Доказательство:
      Открыть/закрыть
    Проверим этот миф на примере "format vs strcat", сравним скрепление 2 и более строк.
    И, в отличие от предыдущего мифа, код будет проверяться на скорость с помощью профайлера.
    Метод с использованием функции format:
    PHP код:
    new string[128];
    format(stringsizeof(string), "%s%s"s1s2); 
    Метод с использованием strcat:
    PHP код:
    new string[128];
    string s1;
    strcat(strings2); 
    Код с использованием strcat несколько объёмнее, чем с format, и будет ещё объёмнее, если нужно будет соединить не 2, а 3 и более строк, т.к. для каждой новой строки нужен будет отдельный вызов strcat.
    Также обратите внимание: константы s1 и s2 не объявлены.
    С ними мы разберёмся позже, пока что нужно ещё разобраться с измерением скорости выполнения кода из обоих методов.
    Для такого измерения прекрасно подойдёт профайлер:
    PHP код:
    /*Настройки.*/
    const PROFILE_ITERATIONS_MAJOR 10_000;
    const 
    PROFILE_ITERATIONS_MINOR 1_000;

    new const 
    code_snippets_names[2][] =
    {
        {
    "format (2)"},
        {
    "strcat (2)"}
    };

    #define Prerequisites();\
        
    static const s1[] = "1234567890123456789012345678901234567890";\
        static const 
    s2[] = "1234567890123456789012345678901234567890";\
        new 
    str[256];

    #define CodeSnippet1();\
        
    format(strsizeof(str), "%s%s"s1s2);

    #define CodeSnippet2();\
        
    str s1strcat(strs2);
    /*Конец настроек.*/ 
    Результаты профилирования:
    Код:
    Тестирование: <format (2)> vs <strcat (2)>
    Режим: интерпретируемый, 10000x1000 итераций.
    format (2): 8406
    strcat (2): 2811
    Как видно из результатов, метод с использованием strcat работает более 2 раз быстрее, чем format.
    И это несмотря на то, что метод с format более лаконичен в плане объёма исходного кода.
    Справедливости ради, следует отметить, что чем больше строк нужно соединить, тем меньше выигрыш при использовании strcat.
    Поэтому при сцеплении 8 и более строк format вырывается вперёд:
    PHP код:
    /*Настройки.*/
    const PROFILE_ITERATIONS_MAJOR 10_000;
    const 
    PROFILE_ITERATIONS_MINOR 1_000;

    new const 
    code_snippets_names[2][] =
    {
        {
    "format (8)"},
        {
    "strcat (8)"}
    };

    #define Prerequisites();\
        
    static const s1[] = "1234567890123456789012345678901234567890";\
        static const 
    s2[] = "1234567890123456789012345678901234567890";\
        static const 
    s3[] = "1234567890123456789012345678901234567890";\
        static const 
    s4[] = "1234567890123456789012345678901234567890";\
        static const 
    s5[] = "1234567890123456789012345678901234567890";\
        static const 
    s6[] = "1234567890123456789012345678901234567890";\
        static const 
    s7[] = "1234567890123456789012345678901234567890";\
        static const 
    s8[] = "1234567890123456789012345678901234567890";\
        new 
    str[sizeof(s1) * 8];

    #define CodeSnippet1();\
        
    format(strsizeof(str), "%s%s%s%s%s%s%s%s"s1s2s3s4s5s6s7s8);

    #define CodeSnippet2();\
        
    str s1strcat(strs2), strcat(strs3), strcat(strs4);\
        
    strcat(strs5), strcat(strs6), strcat(strs7), strcat(strs8);
    /*Конец настроек.*/ 
    Результат:
    Код:
    Тестирование: <format (8)> vs <strcat (8)>
    Режим: интерпретируемый, 10000x1000 итераций.
    format (8): 20433
    strcat (8): 21238
    Но даже если strcat выигрывает не во всех случаях, то хотя бы в нескольких, причём самых распространённых - соединять 8 и более строк приходится сравнительно редко.

    Рассмотрим ещё один пример: сравнение двух вещественных чисел.
    Образец 1:
    PHP код:
    new FloatFloatrandom(0);
    new 
    bool:b;
    = (== 1.0); 
    Образец 2:
    PHP код:
    new FloatFloatrandom(0);
    new 
    bool:b;
    = (_:== _:1.0); 
    Следует заметить, что в Pawn не предусмотрены инструкции для работы с вещественными числами, для таких операций используются нативные функции (floatcmp для сравнения, floatadd для сложения, floatsub для вычитания, floatmul для умножения и т.д.)
    Поэтому в первом примере сравнение вещественных чисел преобразуется в вызов нативной функции floatcmp, которая их и сравнивает.
    Иными словами, код
    PHP код:
    = (== 1.0); 
    превратится в
    PHP код:
    = (floatcmp(x1.0) == 0); 
    Во втором же примере сравниваются не сами вещественные числа, а их внутренние представления, которые, благодаря замене тегов, воспринимаются, как целые числа.

    Для сравнения производительности снова воспользуемся профайлером:
    PHP код:
    /*Настройки.*/
    const PROFILE_ITERATIONS_MAJOR 100_000;
    const 
    PROFILE_ITERATIONS_MINOR 1_000;

    new const 
    code_snippets_names[2][] =
    {
        {
    "Образец 1"},
        {
    "Образец 2"}
    };

    DoNothing(arg)
    {
        
    #pragma unused arg
    }

    #define Prerequisites();\
        
    new bool:bFloat:Floatrandom(0);\
        
    DoNothing(_:b);// Подавить варнинг 204 (неиспользуемая переменная "b").

    #define CodeSnippet1();\
        
    = (== 1.0);

    #define CodeSnippet2();\
        
    = (_:== _:1.0);
    /*Конец настроек.*/ 
    Результаты тестирования:
    Код:
    Тестирование: <Образец 1> vs <Образец 2>
    Режим: интерпретируемый, 100000x1000 итераций.
    Образец 1: 8404
    Образец 2: 3025
    Результаты того же тестирования, только с JIT-компиляцией:
    Код:
    Тестирование: <Образец 1> vs <Образец 2>
    Режим: с JIT-компиляцией, 100000x1000 итераций.
    Образец 1: 1270
    Образец 2: 384
    Итак, в обоих рассмотренных примерах быстрее работают именно те образцы, в которых больше кода.

    На практике же встречается ещё больше техник.
    Пример: кэширование никнеймов игроков при подключении к серверу.
    На само запоминание никнейма может уйти какое-то время. Да и кода может оказаться предостаточно (перехваты OnPlayerConnect, OnPlayerDisconnect, GetPlayerName, SetPlayerName).
    С другой стороны, этим можно ускорить получение никнеймов игроков, заменив вызовы GetPlayerName на обращения к массиву с кэшированными никами.
    Похожую картину можно наблюдать в инклуде foreach.inc от Y_Less: много кода, затраты на добавление и удаление игроков из итератора, но в противовес получаем крайне эффективный метод перебора подключенных игроков.

    Как результат, утверждение о том, что чем меньше кода, тем больше производительность - неверно. Что и требовалось доказать.

    Вывод: производительность алгоритма ни коим образом не зависит от размера исходного кода.
    Самый адекватный способ узнать пользу той или иной реализации одного и того же алгоритма - сравнить время их выполнения в тех или иных ситуациях. Для таких целей прекрасно подойдёт профайлер.


    Специально для Pro-Pawn.ru
    Копирование данной статьи на других ресурсах без разрешения автора запрещено!
    Индивидуально в PM и Skype по скриптингу не помогаю. Задавайте все свои вопросы здесь (click).
    SA-MP 0.4 is a lie

  2. 10 пользователя(ей) сказали cпасибо:
    $continue$ (20.10.2015)Anton Styazhkin (20.10.2015)BadPawn (16.04.2016)Disinterpreter (20.10.2015)George (21.10.2015)Jackal (23.10.2015)MaKcuM (12.01.2017)Osetin (19.10.2015)Seregamil (20.10.2015)[ForD] (20.10.2015)
 

 

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •