Здравствуйте, chaotic-kotik, Вы писали:
CK>Здравствуйте, Serginio1, Вы писали:
S>> Еще раз С++ выигрывает за счет инлайнинга это известно всем. Шаблоны в отличие от дженериков по сути раскручиваются в исходный код с инлайнингом методов. S>>Вот и вся магия. Это же раскручивание можно сделать и для дженериков. Большой то разницы нет. Просто в .Net еще большие тормоза из-за рефлексии, так как при оптимизации кода нужно предоставить доступ для отображения. Поэтому в .Net Native рефлексию сильно ограничили вплоть до полного отказа.
CK>MS не может добить оптимизатор VC++ до уровня gcc четырехлетней давности (нет нормальной векторизации и девиртуализации). Как можно от них ждать чего-то интересного в .net native?
Ну если доведут до .net native до gcc четырехлетней давности будет тоже неплохо
Посмотрим. Время покажет. Во всяком случае движение есть.
и солнце б утром не вставало, когда бы не было меня
Re[16]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, Serginio1, Вы писали: S> Еще раз С++ выигрывает за счет инлайнинга это известно всем. Шаблоны в отличие от дженериков по сути раскручиваются в исходный код с инлайнингом методов. S>Вот и вся магия. Это же раскручивание можно сделать и для дженериков. Большой то разницы нет.
Вообще-то разница огромная.
Например замыкания в C++ можно принимать в ФВП по конкретному типу, то есть без всякого динамического полиморфизма — такое элементарно инлайнится. А вот косвенные вызовы на объектах произвольного размера инлайнить на порядки труднее.
Более того, инлайнинг это не единственный плюс относительно производительности — помимо этого например превалирующая value семантика. S> А насчет питона, то он уже стал статически типизированным?
А он и не собирался
Я говорю что если брать сферические рассуждения о гипотетической возможности оптимизировать код с тормозных языков до уровня C++ — то да, теоретически это вполне возможно, даже для динамически типизированных S>Но возможность приблизить скорость выполнения .Net код к C++ это просто небольшой плюсик не более, что бы убрать у С++ ников их главный козырь.
1. Дело-то не в .NET, а в C# — сам язык, его семантика и идиомы не способствуют производительности.
2. Приблизить, то есть убрать некоторые из тормозов — да, возможно. Но выйти на одинаковый уровень — в обозримом будущем маловероятно.
3. Производительность это не единственный козырь C++, помимо этого например кроссплатформенность, и гибкость языка.
пример
Вот например, на Python можно сделать так (будет работать для любых типов имеющих соответствующие операторы):
def add(x, y):
return x + y
def sub(x, y):
return x - y
def apply(f, *args):
return f(*args)
print(apply(apply, apply, apply, add, 1, 2))
print(apply(apply, apply, sub, 11, 2))
Здравствуйте, Evgeny.Panasyuk, Вы писали: EP>Здравствуйте, Serginio1, Вы писали: S>> Еще раз С++ выигрывает за счет инлайнинга это известно всем. Шаблоны в отличие от дженериков по сути раскручиваются в исходный код с инлайнингом методов. S>>Вот и вся магия. Это же раскручивание можно сделать и для дженериков. Большой то разницы нет. EP>Вообще-то разница огромная. EP>Например замыкания в C++ можно принимать в ФВП по конкретному типу, то есть без всякого динамического полиморфизма — такое элементарно инлайнится. А вот косвенные вызовы на объектах произвольного размера инлайнить на порядки труднее. EP>Более того, инлайнинг это не единственный плюс относительно производительности — помимо этого например превалирующая value семантика.
Так и в C# тоже можно. Так же статически можно определить передаваемый тип. Другое дело, когда в динамике принимается интерфейс.
Отсутствие инлайна основная проблема. Для оптимизации никто не запрещает использовать структуры. Да проблема с массивами на стеке (в классе), но это уже мелочи. S>> А насчет питона, то он уже стал статически типизированным? EP>А он и не собирался EP>Я говорю что если брать сферические рассуждения о гипотетической возможности оптимизировать код с тормозных языков до уровня C++ — то да, теоретически это вполне возможно, даже для динамически типизированных
Ну MS то собирается и делает определенные шаги. S>>Но возможность приблизить скорость выполнения .Net код к C++ это просто небольшой плюсик не более, что бы убрать у С++ ников их главный козырь. EP>1. Дело-то не в .NET, а в C# — сам язык, его семантика и идиомы не способствуют производительности. EP>2. Приблизить, то есть убрать некоторые из тормозов — да, возможно. Но выйти на одинаковый — в обозримом будущем маловероятно. EP>3. Производительность это не единственный козырь C++, помимо этого например кроссплатформенность, и гибкость языка. EP>
пример
EP>Вот например, на Python можно сделать так (будет работать для любых типов имеющих соответствующие операторы): EP>
EP>def add(x, y):
EP> return x + y
EP>def sub(x, y):
EP> return x - y
EP>def apply(f, *args):
EP> return f(*args)
EP>print(apply(apply, apply, apply, add, 1, 2))
EP>print(apply(apply, apply, sub, 11, 2))
EP>
Это все шаблоны. В дженериках можно ввести ограничения. Дп будет не так красиво,
В C# нужно делать контракты, что то типа
T <T>add(T x, T y):where where T : IAdd
{ return x.add(y)}
Но во время компиляции при известном типе x.add(y) будут инлайняться.
Можно по аналогии с расширениями так же добавить аналог утиной типизации.
public static class <int>Extension:IAdd
{
int add(int y){this+y}
static int add(int x,y){x+y}
}
В С++ тебе все равно делать перегрузки для +,++ итд.
Аналогично можно сделать и для C#. Просто когда они озаботятся инлайнингом думаю появятся и новые конструкции.
Во всяком случае VladD2 еще на Видби показывал варианты и с инлайнингом где интерфейс реализовывался на структуре
и солнце б утром не вставало, когда бы не было меня
Re[14]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, CreatorCray, Вы писали:
CC>Здравствуйте, koandrew, Вы писали:
K>>Однако даже там крайне полезно хотя бы в общих чертах знать ассемблер этой платформы CC>Знать — обязательно, тут даже вопроса стоять не должно. CC>Но писать на нём не придётся ничего в 99% случаев.
Для меня С++ светлое будующее. Пока приходится обходится C. Причем приделываю и объектные подходы как в древнии времена. Но на ассемблере уже несколько лет ничего не делал, и не собираюсь.
Re[18]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, Serginio1, Вы писали:
S>>> Еще раз С++ выигрывает за счет инлайнинга это известно всем. Шаблоны в отличие от дженериков по сути раскручиваются в исходный код с инлайнингом методов. S>>>Вот и вся магия. Это же раскручивание можно сделать и для дженериков. Большой то разницы нет. EP>>Вообще-то разница огромная. EP>>Например замыкания в C++ можно принимать в ФВП по конкретному типу, то есть без всякого динамического полиморфизма — такое элементарно инлайнится. А вот косвенные вызовы на объектах произвольного размера инлайнить на порядки труднее. EP>>Более того, инлайнинг это не единственный плюс относительно производительности — помимо этого например превалирующая value семантика. S> Так и в C# тоже можно. Так же статически можно определить передаваемый тип.
C++:
template<typename F>
auto foo(F f)
{
return f();
}
int main()
{
auto x = 0;
return foo([=]{ return x; });
}
Здесь внутри foo, ещё до всяких оптимизаторов, известен и конкретный тип замыкания F, и его размер, и конкретный вызываемый метод.
Аналог на C# в студию.
Re[18]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, Serginio1, Вы писали:
S>Отсутствие инлайна основная проблема. Для оптимизации никто не запрещает использовать структуры. Да проблема с массивами на стеке (в классе), но это уже мелочи.
Чтобы работал GC компилятор дотнета вставляет дополнительный код (барьеры). Чтобы проверять на выход за границу массива компилятор дотнета генерирует кучу проверок. Помнится, несколько лет назад, JIT в дотнете не мог очень простой цикл развернуть. А вы тут ждете каких-то чудес производительности от инлайна делегатов. Чтобы приблизиться к С++ по производительности нужно не только компилятор исправить, но и например переписать полностью стандартную библиотеку таким образом, чтобы она не выделяла память на каждый чих без лишней необходимости и чтобы работа на низком уровне абстракции (работа с памятью напрямую) не выглядела так, как она выглядит сейчас. На С++ ведь реально код на порядок проще получается, если нужно писать что-то близкое к железу и производительное.
Re[19]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Serginio1, Вы писали:
S>>>> Еще раз С++ выигрывает за счет инлайнинга это известно всем. Шаблоны в отличие от дженериков по сути раскручиваются в исходный код с инлайнингом методов. S>>>>Вот и вся магия. Это же раскручивание можно сделать и для дженериков. Большой то разницы нет. EP>>>Вообще-то разница огромная. EP>>>Например замыкания в C++ можно принимать в ФВП по конкретному типу, то есть без всякого динамического полиморфизма — такое элементарно инлайнится. А вот косвенные вызовы на объектах произвольного размера инлайнить на порядки труднее. EP>>>Более того, инлайнинг это не единственный плюс относительно производительности — помимо этого например превалирующая value семантика. S>> Так и в C# тоже можно. Так же статически можно определить передаваемый тип.
EP>C++: EP>
Здесь внутри foo, ещё до всяких оптимизаторов, известен и конкретный тип замыкания F, и его размер, и конкретный вызываемый метод. EP>Аналог на C# в студию.
T foo<T>(Func<T> f)
{
return f();
}
int main()
{
var x = 0;
return foo<int>(=>{ return x; });
}
Не знаю может ли вывести тип дженерика, но по идее и так должно работать.
Я например в своей компоненте вывожу тип в рантайме.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
EP>>Здесь внутри foo, ещё до всяких оптимизаторов, известен и конкретный тип замыкания F, и его размер, и конкретный вызываемый метод. EP>>Аналог на C# в студию S>
S> T foo<T>(Func<T> f)
S>{
S> return f();
S>}
S>
О чём и речь — у тебя внутри foo один тип для разных замыканий с одинаковой сигнатурой — а значит динамический полиморфизм и прочие индерекции, которые на порядок сложнее оптимизировать
Re[19]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, chaotic-kotik, Вы писали:
CK>Здравствуйте, Serginio1, Вы писали:
S>>Отсутствие инлайна основная проблема. Для оптимизации никто не запрещает использовать структуры. Да проблема с массивами на стеке (в классе), но это уже мелочи.
CK>Чтобы работал GC компилятор дотнета вставляет дополнительный код (барьеры). Чтобы проверять на выход за границу массива компилятор дотнета генерирует кучу проверок. Помнится, несколько лет назад, JIT в дотнете не мог очень простой цикл развернуть. А вы тут ждете каких-то чудес производительности от инлайна делегатов. Чтобы приблизиться к С++ по производительности нужно не только компилятор исправить, но и например переписать полностью стандартную библиотеку таким образом, чтобы она не выделяла память на каждый чих без лишней необходимости и чтобы работа на низком уровне абстракции (работа с памятью напрямую) не выглядела так, как она выглядит сейчас. На С++ ведь реально код на порядок проще получается, если нужно писать что-то близкое к железу и производительное.
Еще раз повторю. Время идет и все меняется. Те же циклы типа
for(int i=0;i<ar.Length,i++)
var a=ar[i];
Никаких проверок не будет. А для работы с матрицами есть SIMD.
Речь, не идет о замене C++. Речь идет о увеличении производительности .Net кода.
Большинству не нужна скорость выполнения, а нужна скорость разработки. Я 1С ник, и в большей степени у нас упирается в БД. А вот легкость создания клиент-серверного имеет большее значение
и солнце б утром не вставало, когда бы не было меня
Re[21]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Serginio1, Вы писали:
EP>>>Здесь внутри foo, ещё до всяких оптимизаторов, известен и конкретный тип замыкания F, и его размер, и конкретный вызываемый метод. EP>>>Аналог на C# в студию S>>
S>> T foo<T>(Func<T> f)
S>>{
S>> return f();
S>>}
S>>
EP>О чём и речь — у тебя внутри foo один тип для разных замыканий с одинаковой сигнатурой — а значит динамический полиморфизм и прочие индерекции, которые на порядок сложнее оптимизировать
На данном этапе да.
Но мы то говорим о компиляторе в стиле C++. А там
return x>>
проинлайнить не проблема на уровне исходников. Хотя можно делать некую промежуточный вариант куда будет вставляться IL код.
Главное, что контракт соблюден.
и солнце б утром не вставало, когда бы не было меня
Re[22]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, Serginio1, Вы писали:
EP>>>>Здесь внутри foo, ещё до всяких оптимизаторов, известен и конкретный тип замыкания F, и его размер, и конкретный вызываемый метод. EP>>>>Аналог на C# в студию S>>>
S>>> T foo<T>(Func<T> f)
S>>>{
S>>> return f();
S>>>}
S>>>
EP>>О чём и речь — у тебя внутри foo один тип для разных замыканий с одинаковой сигнатурой — а значит динамический полиморфизм и прочие индерекции, которые на порядок сложнее оптимизировать S> На данном этапе да. S>Но мы то говорим о компиляторе в стиле C++. А там
return x>>
проинлайнить не проблема на уровне исходников.
Подобные штуки (динамический полиморфизм) и компиляторы C++ инлайнят только в простейших вариантах — если же добавить простую аллокацию на пути или что-то подобное, то это становится серьёзным барьером для инлайнинга (тут разве что помогает PGO, да и то частично).
То есть ещё раз, код C# чисто по построению намного труднее оптимизировать — для оптимизаций до уровней аналогичных C++ нужно либо язык модифицировать, либо делать оптимизаторы намного более мощные чем оптимизаторы C++
Re[20]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, Serginio1, Вы писали:
S> Еще раз повторю. Время идет и все меняется. Те же циклы типа S>
S>for(int i=0;i<ar.Length,i++)
S> var a=ar[i];
S>
S>Никаких проверок не будет. А для работы с матрицами есть SIMD.
Компилятор С++ вообще этот цикл вырежет, так как он ничего не делает. Либо векторизует, если `a` дальше используется в вычислениях, причем вкорячит туда такой код, который сможет работать даже в случае если массив не выровнен. Ну а компилятор сишарпа даже проверки сможет вырезать только в простых случаях (линейно бежим по массиву). Если есть inderection (вычисляем значение i по таблице, например) — то он не вырежет ничего и будет каждый индекс проверять.
Re[21]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, chaotic-kotik, Вы писали:
CK>Компилятор С++ вообще этот цикл вырежет, так как он ничего не делает. Либо векторизует, если `a` дальше используется в вычислениях, причем вкорячит туда такой код, который сможет работать даже в случае если массив не выровнен. Ну а компилятор сишарпа даже проверки сможет вырезать только в простых случаях (линейно бежим по массиву). Если есть inderection (вычисляем значение i по таблице, например) — то он не вырежет ничего и будет каждый индекс проверять.
В С++ — другая крайность. Индекс вообще проверяться не будет (вычислили значение i по таблице неправильно и бабах).
А если захочешь безопасностьи то вместо vect[i] будешь использовать vect.at(i) и компилятор С++ столкнётся с той же бедой, что и сишарп.
По-моему, в подавляющем большинстве случаев важнее не бабахать, чем вырезать.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[22]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, ·, Вы писали:
·>В С++ — другая крайность. Индекс вообще проверяться не будет (вычислили значение i по таблице неправильно и бабах). ·>А если захочешь безопасностьи то вместо vect[i] будешь использовать vect.at(i) и компилятор С++ столкнётся с той же бедой, что и сишарп.
Есть третий вариант: во время разработки и тестирования включаются asserts, checked iterators и прочий defensive programming, которые помогают отлавливать подобные проблемы http://coliru.stacked-crooked.com/a/b70a433c52e5b336
#include <vector>
int main()
{
std::vector<int> xs;
xs[5];
}
/usr/local/include/c++/6.1.0/debug/vector:415:
Error: attempt to subscript container with out-of-bounds index 5, but
container only holds 0 elements.
Objects involved in the operation:
sequence "this" @ 0x0x7fff719fd1d0 {
type = std::__debug::vector<int, std::allocator<int> >;
}
bash: line 7: 14850 Aborted (core dumped) ./a.out
Re[23]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>·>В С++ — другая крайность. Индекс вообще проверяться не будет (вычислили значение i по таблице неправильно и бабах). EP>·>А если захочешь безопасностьи то вместо vect[i] будешь использовать vect.at(i) и компилятор С++ столкнётся с той же бедой, что и сишарп. EP>Есть третий вариант: во время разработки и тестирования включаются asserts, checked iterators и прочий defensive programming,
А во время эксплуатации что делать? Молитву о здравии заказывать? Довольно рисково иметь разный код в дебаге и релизе.
assert вот как-то не прижился в managed языках...
EP>которые помогают отлавливать подобные проблемы
Мало они помогают. Переносят проблемы с плеч компилятора на плечи программиста. Угадай — кто чаще ошибается?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[17]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, chaotic-kotik, Вы писали:
CK>MS не может добить оптимизатор VC++ до уровня gcc четырехлетней давности (нет нормальной векторизации и девиртуализации).
А тот же gcc всё никак не допрыгнет до intel compiler по качеству генерируемого кода.
Я периодически смотрю в assembler output от гнуса и очень часто там печалька. В частности почему то он очень любит сливать в память тогда как полно свободных регистров.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[24]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, ·, Вы писали:
EP>>·>В С++ — другая крайность. Индекс вообще проверяться не будет (вычислили значение i по таблице неправильно и бабах). EP>>·>А если захочешь безопасностьи то вместо vect[i] будешь использовать vect.at(i) и компилятор С++ столкнётся с той же бедой, что и сишарп. EP>>Есть третий вариант: во время разработки и тестирования включаются asserts, checked iterators и прочий defensive programming, ·>А во время эксплуатации что делать? Молитву о здравии заказывать?
Тестировать код — это нужно в любом случае. Все эти defensive примочки от багов не исцеляют, а лишь смягчают последствия фейла.
·>Довольно рисково иметь разный код в дебаге и релизе.
Тестируй и debug и release если есть какие-то сомнения в отсутсвии side-effect'ов у assert'ов.
·>assert вот как-то не прижился в managed языках...
ЕМНИП Sinix рассказывал что использует их во всю как раз в managed языке.
EP>>которые помогают отлавливать подобные проблемы ·>Мало они помогают. Переносят проблемы с плеч компилятора на плечи программиста. Угадай — кто чаще ошибается?
Задача писать корректный код лежит на плечах программиста, и никакие defensive штуки не превратят некорректный код в корректный. Максимум в чём они помогают — это раннее определение уже свершившегося бага, да и то в рантайме
AS>Собственно, сборка мусора в Rust есть (опционально), а такого мощного статического анализатора в C# нет.
Зарплата Senior Staff Engineer (Java/JavaScript) в Google ~ 250k в год
Зарплата Senior Engineer (Java/JavaScript) в Netflix ~ 350k в год
Зарплата Senior .Net Engineer в Microsoft ~ 80k в год
Как вы полагаете какие люди идут в си шарп? Правильно он сначала был велоинструктором 10 лет, потом программистом Шарепоинта на дельфи. Потом он еще 10 лет познавал гит (как некоторые эксперты си шарп на рсдн, до сих пор отсмеяться не могу).
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>То есть ещё раз, код C# чисто по построению намного труднее оптимизировать — для оптимизаций до уровней аналогичных C++ нужно либо язык модифицировать, либо делать оптимизаторы намного более мощные чем оптимизаторы C++
Язык тут не при чем. Машинный код генерируется из IL. В нем все указанные тобой оптимизации делаются элементарно.
Но у JIT нет столько времени на пребразования, как у компилятора C++. Поэтому оптимизации оставляют желать лучшего. В теории могли бы делать омтипизации в ngen, но посчитали что одинаковый выхлоп ngen и jit важнее, чем пару мсек скорости.
В Java и JS пошли по пути "HotSpot" — повторная компиляция кусков кода на основе профиля использования.
Для .NET придумали другой способ — генерировать C++ код и потом его компилировать (.NET Native).
Re[24]: Да ну и фиг с этой Java-ой. .Net будет убит Rust-ом
Здравствуйте, gandjustas, Вы писали:
EP>>То есть ещё раз, код C# чисто по построению намного труднее оптимизировать — для оптимизаций до уровней аналогичных C++ нужно либо язык модифицировать, либо делать оптимизаторы намного более мощные чем оптимизаторы C++ G>Язык тут не при чем.
Именно язык тут и при чём. Если писать на C++ в стиле C# — динамические замыкания, динамический IEnumerable, множество индерекций по памяти — то получим примерно такие же тормоза
G>Машинный код генерируется из IL. В нем все указанные тобой оптимизации делаются элементарно. G>Но у JIT нет столько времени на пребразования, как у компилятора C++.
Что мешает сразу генерировать оптимизированный IL?
Я выше привёл пример с трансляцией C++ -> JS. JS ещё "хуже" IL, но тем не менее он работает быстро. Можно взять этот JS выхлоп и перевести на C# — и он там тоже будет работать быстро, несмотря ни на какой IL