1. C# / Говнокод #7855

    +964

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    using System;
    using System.Reflection;
    using System.Reflection.Emit;
    
    namespace DynUnloop
    { // Суммирование в цикле
      class SumLooping
      { public int Summ(int valMax)
        { int result = 0;
          for (int i = 0; i <= valMax; i++)
            result += i;
          return result;
        }
      }
    
      // Плоское суммирование
      class SumFlat
      { interface ISumCode
        { int ComputeSumm(int valMax);
        }
        void WriteCode(int valMax)
        { AssemblyName assemblyName = new AssemblyName();
          assemblyName.Name = "SumFlatAssembly";
    
          AssemblyBuilder assemblyBuilder = 
            AppDomain.CurrentDomain.DefineDynamicAssembly(
            assemblyName, AssemblyBuilderAccess.Run);
    
          ModuleBuilder moduleBuilder = 
            assemblyBuilder.DefineDynamicModule("SumFlatModule");
    
          TypeBuilder typeBuilder = 
            moduleBuilder.DefineType("SumFlatClass"
                        , TypeAttributes.Public);
    
          typeBuilder.AddInterfaceImplementation(typeof(ISumCode));
    
          /// Задаём возвращаемое зачение и параметр
          Type[] paramTypes = { typeof(int) };
          Type   returnType = typeof(int);
    
          MethodBuilder methodBuilder = 
            typeBuilder.DefineMethod("ComputeSumm"
              , MethodAttributes.Public 
              | MethodAttributes.Virtual
              , returnType, paramTypes);
    
          ILGenerator il = methodBuilder.GetILGenerator();
    
          // Генерируем плоский код.
          il.Emit(OpCodes.Ldc_I4, 0);
          for (int i = 1; i <= valMax; i++)
          { il.Emit(OpCodes.Ldc_I4, i);
            il.Emit(OpCodes.Add);
          }
          il.Emit(OpCodes.Ret);
    
          // Перекрываем метод ComputeSumm и создаём тип SumFlatClass.
          MethodInfo methodInfo = 
                     typeof(ISumCode).GetMethod("ComputeSumm");
          typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);
          typeBuilder.CreateType();
    
          /// Код готов, создаём объект и берем его интерфейс.
          code = (ISumCode)assemblyBuilder.CreateInstance("SumFlatClass");
        }
    
        public int Summ(int val)
        { if (this.code == null)
            WriteCode(val);
          return this.code.ComputeSumm(val);
        }
    
        ISumCode code;
      }

    Оригинальный стиль кода и комментарии сохранёны. (с), или как там.
    В коде - разворачивание цикла в "плоский" IL код, который, как доказывается должен выигрывать по производительности.

    Запостил: Elvenfighter, 13 Сентября 2011

    Комментарии (47) RSS

    • valMax*(valMax+1)/2 посчитать не судьба?
      Ответить
      • Слишком просто для того, кто умеет генерить "плоский" код.
        Ответить
    • узнаю брата Колю. Знания есть а ума нет
      Ответить
    • Взять объект за интерфейс еще уметь надо :D
      Ответить
    • Шедевр просто:)
      Ответить
    • Как-то убого в C# сделана "кодогенерация на ходу". Только асмокомандами. Почему не высокоуровневыми конструкциями?
      Ответить
      • А какой язык позволяет делать кодогенерацию высокоуровневыми инструкциями? Вызовы компилятора для строки с текстом программы или eval во всяких пыхопитонах не предлагать.
        Ответить
        • Никакой, потому я и ругаюсь. Также про этот момент есть в статье Криса Касперски "языки, которые мы потеряли".
          А возможность очень полезная, и тогда замыкания (жалкое, тормозное подобие этой фичи) станут не нужны.
          Ответить
        • Шёпотом: "Nemerle"...
          Ответить
          • У него же все фишки периода компиляции, нет?
            Ответить
            • Мнэ-э... Мне не совсем понятно, что тебе нужно. Переформулируй вопрос.
              К сожалению, я пока лишь присматриваюсь к Немерле, метапрограммирование в нём ещё толком не освоил. Однако из немерловых макросов действительно доступны всю фишки компилятора. Макросы могут, например, и в базу данных слазить, и куда-нибудь в тырнет обратиться. И это всё в компайл-тайме!
              Ответить
              • тарас хочет наоборот компиляцию в рантайм перенести, а не исполнение в компильтайм.
                Ответить
              • > и куда-нибудь в тырнет обратиться
                error c404: Fatal compilation error. Page not found.
                Ответить
                • Ну а что делать? И такие ошибки могут быть.

                  Просто дело в том, что сейчас в процессе билда сложных приложений скрипты и в базы данных лезут, и прочее. Но пишутся эти билд-скрипты на чём-то левом, не на родном языке приложения, будь то C++,C#,Java. Используются препроцессоры, make-файлы, батники, питоны, баши и прочее. Естественно, это не упрощает процесс разработки. И это требует наличие в системе интерпретаторов этих скриптовых языков. То есть скачаешь опенсорсную софтину на Си, а для её компиляции ещё и кучу скриптовых языков придётся поставить.

                  В отличие от них, для компиляции немерловых программ достаточно единственного компилятора, который выполнит всё то же самое.
                  Ответить
      • В C# можно не только асмокомандами. Можно и в виде текста задавать код для последующей компиляции. А можно и собирать код с помощью класса Expression. Тема обширная, в одном комменте не раскроешь.
        Ответить
        • Ну, текстом тоже не очень, потому что он вынуждает имена переменных помнить при работе приложения. Лучше уж с синтаксисом замыканий.
          Ответить
          • Если интересно, глянь ссылки:
            http://msdn.microsoft.com/ru-ru/library/system.linq.expressions.expression.aspx - зацени список методов, с помощью которых можно конструировать выражения.
            http://msdn.microsoft.com/en-us/library/bb397951.aspx - небольшие примеры кода.
            То что нужно?

            Да, выглядит громоздко. Но тут ещё дело в том, что в Лиспе - динамическая типизация. А в C# строгая статическая, поэтому кодогенерация как ни крути будет сложнее.
            Ответить
          • Да, и вот ещё что. Спроси об этом у создателей Немерла. Они на RSDN тусуются.
            Наверняка обзовут блаб-программистом, но ответят :).


            P.S. хм, Страйко, что значит:
            Ошибка компиляции комментария:
            1. csrf verification error
            ?
            Ответить
            • Вот круто будет если TarasB начнёт писать на Nemerle. Сколько тут троллинга начнётся... Ибо возможности и выразительность кода в Nemerle дадут фору многим языкам.
              Ответить
              • Немерле — вчерашний день. Настоящие крутые программисты пишут на ультракоротком и ультрапонятном языке программирования РС!
                Ответить
                • можно ссылку? что-то ничего не нагуглилось...
                  Ответить
                  • http://rsdn.ru/forum/flame.comp/4086890.flat.aspx

                    Только осторожно, пристегнитесь. А то свалитесь под стол.
                    Ответить
                    • Это БОМБА!
                      Ответить
                    • Блин, я что-то забыл... Свалился под стол...
                      Ответить
                    • очень крутое говно!
                      Ответить
                    • Его голова просит кирпича за наглость высказываний.
                      Ответить
                    • http://code.google.com/p/rsinterpretator/source/browse/trunk/RSInterpretator?spec=svn14&r=14
                      Парень жжет: Пусть это будет просто, просто как только можно, но не проще...
                      Ему бы в рекламу абибаса
                      Ответить
                      • помнит, что эйнштейн говорил
                        Ответить
                        • Если вы не можете объяснить это простыми словами, вы не до конца это понимаете (с) Эйнштейн
                          Лучше бы он эту фразу помнил, ибо объяснить он так ничего и не смог(причем никакими словами вообще). Не качественный какой-то тролль попался
                          Ответить
                    • тонко
                      Ответить
                    • А где можно посмотреть на БНФ-нотацию этого языка?
                      Ответить
                    • Там на 5 странице чел очень правильно расчехляет, найдя кучу неоднозначностей, убедительно доказывая, что чудес не бывает.
                      Ответить
                      • Поцак на пару постов ниже демонстрирует всем инфу о своей видяхи с подтверждающим скрином:
                        http://www.gamedev.ru/code/forum/?id=147985#m3
                        Я прямо таки как в музей сходил.
                        Профи пользуют Voodoo. Пока не ретро у тебя видяха. Нечего хвастаться.
                        Ответить
    • Всё-таки правильно говорил дедушка Кнут про преждевременную оптимизацию.

      Не то оптимизируете, товарищи, ох не то.
      Ответить
    • Автору кода надо пропатчить в рантайме свой код ДНК
      Ответить
      • Так можно и третий глаз получить. Сразу в рантайме.
        Ответить
        • ага, бежит чувак, а у него то уй отвалицо, то на лбу вырастет
          Ответить
    • Скажу так: написанный вручную IL-код действительно может оказаться быстрее и/или компактнее, чем выданный компилятором. Так же как и написанный вручную ассемблерный vs язык высокого уровня. Но заниматься этим вряд ли имеет смысл. К тому же JIT-компилятор может вмешаться и подпортить картину.
      Ответить
      • К Фрипаскалю прилагался пример программы, в котором одна и та же функция вычислялась один раз выражением на Паскале, второй раз — на Ассемблере. Ассемблерный код выполнялся в два раза быстрее. Это доказывало слова автора, что написанный вручную код может оказаться быстрее.

        Однако, я скомпилировал этот пример с помощью Виртуалпаскаля и Дельфи. И там, и там паскалевский код выполнялся вдвое быстрее ассемблерного. Сенсация! Теория опровергнута!

        Дизассемблировал поделки этих компиляторов... После этого переписал пример на Ассемблере — в VP и Дельфи время выполнения оказалось примерно одинаковым. Опубликовать результаты говнокодом или на высер компилятора смотреть будет скучно?

        Из этого должна следовать какая-то мораль. Только пока не могу понять, какая.
        Ответить
        • Накладывайте давайте. Посмотрим. Все равно жеж информация и тема для разговора
          Ответить
        • Мысль такая: не считай себя умнее компилятора, даже если это Дельфи. Да, компилятор Дельфи - не говно, я серьёзно.
          Ответить
          • Тарас, теперь мы ждем, что ты перелогинишься и будешь теперь обсирать компилятор Дельфи
            Ответить
        • Ну да, мораль есть. Простой код - типа сложение двух чисел - человек может написать на ассемблере не менее эффективно, чем выдаст компилятор. Но и не более. А сложный код, в котором, например, используются команды MMX, 3DNow, SSE, человек заколебётся вручную писать. Компилятор это сделает наверняка лучше.

          А результаты давай, публикуй. Может интересно будет обсудить.

          И ещё раз хочу упомянуть JIT: в виртуальных машинах он может любой код переделать на своё усмотрение. Поэтому вылизывать код вручную становится вообще бессмысленно. Ты задашь такой набор команд, а JIT выкинет их нах, и вставит свой.
          Ответить

    Добавить комментарий