LINUX.ORG.RU

lama question on expression tree vs bytecode

 ,


0

1

Привет,

Совсем ламерский вопрос.

http://gameprogrammingpatterns.com/bytecode.html

Там есть такой текст:

Put those together, and what do they spell? S-L-O-W. There’s a reason most programming languages in wide use aren’t based on the Interpreter pattern. It’s just too slow, and it uses up too much memory

С другой стороны вот тут:

1. Decompile IL code for the query at runtime, and turn it into the target language – quite roundabout

2. Enable representing the query’s code as data at runtime by emitting an expression tree at compile-time

(c) http://community.bartdesmet.net/blogs/bart/archive/2009/08/10/expression-tree...

Описано как LINQ разбирает лямбды как раз в синтактическое дерево (а не непосредственно в инструкции IL), чтобы потом скомпилировть. Разве это не будет медленно? Если используется не Ahead-of-Time а Just-in-Time компиляция, разве представление лямбд в ввиде дерева из класс, в котором множество объектов того же самого типа не займет множество места и не затратит множество CPU циклов, чтобы превратить это в bytecode, вместо того, чтобы представить каждое варажение в лямбде непосредственно как инструкцию для виртуальной машины (в данном случае IL) внутри DLL/EXE?

Т.е. не значит ли это что LINQ - это очень медленно? Почему тогда гугл говорит что это не так? Например тут: https://stackoverflow.com/questions/11296439/is-linq-much-slower-than-a-simpl...

★★

Последнее исправление: dissident (всего исправлений: 6)

В общем случае результатом парсинга является AST, и пропускать этот этап - преждевременная оптимизация, которая может кончиться очень плачевно

annulen ★★★★★
()
Ответ на: комментарий от annulen

Т.е. в случае компиляции C# при помощи Mono/.NET - выходом будет IL для C# + AST для лямбд?

Просто например если я скомпилирую X.java в X.class, то если я правильно понимаю там внутри будут иструкции а-ля ассемблер для VM и это быстро и классно, а если я скомпилирую X.cs в X.dll и в X.cs испольщую LINQ, то в DLL будет IL + AST?

Или это вообще все не так работает и в случае JIT и в DLL и в class/jar будет AST?

PS Вопрос реально очень ламерский.. Сорри за это. Хочется понять на очень высоком уровне абстракции почему обычный код C# компилируется в IL а лямбды в AST.

dissident ★★
() автор топика
Последнее исправление: dissident (всего исправлений: 1)
Ответ на: комментарий от annulen

Ладно тогда совсем конкретизируя вопрос:

Expression trees are also used in the dynamic language runtime (DLR) to provide interoperability between dynamic languages and the .NET Framework

(c) https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/exp...

Зачем? Почему нельзя скомпилировать этот гребаный Вижуал Бейсик в IL (как Scala компилируется в .class) а нужно хранить его в DLL в виде громоздкого expression tree?

dissident ★★
() автор топика
Ответ на: комментарий от dissident

Или я вообще все неправильно понял и внутри DLL и в случае LINQ будет IL как следует отсюда: https://stackoverflow.com/questions/3894598/how-is-linq-compiled-into-the-cil Зачем тогда нужны эти expression tree прямо в языке?

dissident ★★
() автор топика
Ответ на: комментарий от dissident

Или это вообще все не так работает и в случае JIT и в DLL и в class/jar будет AST?

AST как правило существует только в памяти в процессе работы компилятора и сериализуется только в специальных целях. Хотя в природе существуют VM, которые выполняют непосредственно AST

Описано как LINQ разбирает лямбды как раз в синтактическое дерево (а не непосредственно в инструкции IL), чтобы потом скомпилировть. Разве это не будет медленно?

Если они используют в оптимизаторе на входе AST вместо IL при условии что IL можно без проблем получить, это значит что в IL потеряна важная для оптимизатора информация (сори я в сортах этих дотнет-штук не силен, могу только за общие принципы поболтать)

annulen ★★★★★
()
Ответ на: комментарий от dissident

Вангую что дело в автокомплите и т.п. для IDE, им было влом впихивать всю бейсиковую семантику в IL и они решили тупо рядом AST положить

annulen ★★★★★
()
Ответ на: комментарий от annulen

Я так понял, что они берут LINQ query, превращают ее в expression tree, хранят это в DLL, потом это десериализируют и превращают например в SQL. Или берут Python, превращают в AST, сериализируют в DLL, потом читают его в память и выполняют и так работает весь этот Dynamic Language Runtime.

Я просто не могу понять разве это не медленно?

Почему в JVM существует и Scala и Groovy а expression tree на уровне языка Java не видно.

Но я действительно полный ламер тут и просто хочу понять почему они сделали так а не иначе. И действительно ли в JVM Groovy например компилируется в байткод, а в Mono/.NET в expression tree.

dissident ★★
() автор топика

Expression tree это просто удобное промежуточное представление. Оно может быть использовано в разных сценариях.

Например, когда компилятор встречает лямба выражение которое приводится к типу Expression<T> вместо фактической компиляции он генерирует код, который создаёт expression описывающий соответствующую лямбду. В момент выполнения созданный expression можно странслировать в другой язык, например в SQL. Получаем цепочку преобразований: C# -> Expression Tree -> SQL

Второй возможный сценарий, ты парсишь какой-нибудь свой DSL и потом создаёшь в рантайме expression tree на его основе. Полученный объект expression tree можно скомпилировать стандартными средствами уже в обычный CLR байткод (aka IL), который выполняется рантаймом через JIT-компиляцию с скоростью скомпилированной C# программы. В принципе возможно генерировать байткод в рантайме напрямую, но это более сложный подход в написании и отладке. Для наколеночных DSL типа простой арифметики он избыточен. В этом сценарии цепочка преобразований другая: DSL -> Expression Tree -> IL -> машинный код

Могут быть и другие сценарии использования, важно что expression trees это часть стандартной библиотеки и функциональность компилятора.

Про DLR ничего не скажу, не пользовался

anonymous
()
Ответ на: комментарий от anonymous

Например, когда компилятор встречает лямба выражение которое приводится к типу Expression<T> вместо фактической компиляции он генерирует код, который создаёт expression описывающий соответствующую лямбду. В момент выполнения созданный expression можно странслировать в другой язык, например в SQL. Получаем цепочку преобразований: C# -> Expression Tree -> SQL

Т.е. правильно ли я понимаю, что LINQ - это компромисс? Вместо того, чтобы компилировать лямбды прямо в целевой байткод (я не имею ввиду, что во время компиляции нету промежуточного этапа представления лямбд в виде AST, я имею ввиду, что конечным результатом работы компилятора является не байткод, а AST) они «компилируются» в AST и таки да, кладутся в DLL в виде громоздкого AST?

Если так то:

1. Так же ли работает IronPython? «Компилируется» ли он в DLL в виде AST?

2. Почему Groovy, Scala и прочие JVM языки не используют такое решение, а компилируются в байткод?

3. Почему в стандартной библиотеке Явы нету механизма представления конструкций языка в виде AST?

dissident ★★
() автор топика
Последнее исправление: dissident (всего исправлений: 4)
Ответ на: комментарий от dissident

Т.е. правильно ли я понимаю, что LINQ - это компромисс?

Нет, это просто инструмент, всё компилируется в байткод по дефолту, пока ты сам не захочешь expression tree

1. Так же ли работает IronPython? «Компилируется» ли он в DLL в виде AST?

без понятия

2. Почему Groovy, Scala и прочие JVM языки не используют такое решение, а компилируются в байткод?

3. Почему в стандартной библиотеке Явы нету механизма представления конструкций языка в виде AST?

потому что у них нет такого инструмента, не заимплементили, не захотели, решили что не нужно и т.д.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.