company_banner

C++ против C#



    Всем известно, что нет ничего глупее споров «какой язык лучше». Например, лучше для чего? Разные языки успешны в разных нишах — и бессмысленно делать категоричные выводы, не учитывая это.

    Но что получится, если обратиться к опытным специалистам, которые сами всё это понимают, и попросить их всё-таки устроить холивар «C++ vs C#»? Оказывается, можно узнать много любопытных деталей. Слово «кроссплатформенный» можно по-своему применить к обоим языкам, но что это значит на практике? Активно ли сейчас развивается С++? Ломал ли C# когда-либо обратную совместимость? Ответы могут быть очевидны для тех, кто уже глубоко погружён в оба языка сразу, но таких людей немного — а все остальные узнают что-то новое.

    Со стороны C++ поучаствовал Сергей sermp Платонов — председатель программного комитета конференции C++ Russia. Сторону C# представлял Анатолий Кулаков — он входит и в ПК конференции DotNext, и в число лидеров DotNetRu. А ведущим дискуссии, в жизни которого сосуществуют оба этих мира, стал Дмитрий mezastel Нестерук.




    Дмитрий: Добрый день, коллеги. Добро пожаловать на неформальные посиделки на тему языков программирования. В интернете нам постоянно напоминают, что сравнивать языки нельзя. И сегодня мы займёмся именно тем, что делать нельзя: сравним С++ с C# и .NET, их плюсы и минусы. Представьтесь, пожалуйста.

    Анатолий: Меня зовут Анатолий, и я сегодня буду топить за C#, потому что я занимаюсь этим языком с первых его версий и, кажется, знаю о нём всё.

    Сергей: Привет, меня зовут Сергей, я сегодня буду топить за C++. Дима правильно сказал, что сравним плюсы и минусы. «Плюсами» все называют известно что, получается, что C# в данной дискуссии будет минусом. Правильно, Анатолий?

    Анатолий: У C# на два плюса больше! Поэтому я думаю, что это эволюционное развитие плюсов, которые уже морально устарели и не способны конкурировать практически нигде.



    Образование


    Дмитрий: У меня первый топик для нашей дискуссии. Представьте, что в университет приходят новые студенты, им нужен первый язык. Как вы считаете, каким должен быть первый язык, который люди получают на первом курсе: C++, C# или вообще ассемблер?

    Сергей: Я какое-то время преподавал, поэтому у меня есть устоявшееся мнение. Понимаю, что мы здесь собрались дискутировать, какой язык лучше, и я выступаю за C++… Но для обучения C++ нужно понимать архитектуру компьютера. И с этим большая проблема преподавания у студентов (по крайней мере, в том вузе, где я преподавал). А чтобы преподавать алгоритмы и прочее, наверное, надо что-то, что не акцентирует внимание на инфраструктуре, на самом языке. Вот Eiffel был попыткой сделать такое, но там тоже много магии. Поэтому я бы сказал, что из двух наших языков ни тот, ни другой не подходят.

    Программирование — оно разное, и преподают не «программирование», а алгоритмы, структуры данных и так далее. Возможно, что имеет смысл на каждом предмете выбирать свой инструмент. По какому-нибудь Lisp разбираться со структурами данных. А C++, соответственно, давать уже после того, как студенты поймут что-то про архитектуру. И тогда можно будет понять, зачем вся эта боль и страдание. Я даже не стану спорить с тем, что плюсы — это про боль.

    Анатолий: Да, я полностью согласен, что нужно разделять предметы, а не ставить это в «программирование» и одним языком всё забивать. Но если вы дойдёте до уровня, когда изучили базисы, основы, алгоритмы, и начинаете выбирать какой-то промышленный язык, то здесь, безусловно, C# будет намного лучше. Потому что он вас не заставляет учить всю эту муть на уровне архитектур, байтов памяти и прочих «закатов солнца вручную». Он даёт сразу понятный язык, простой синтаксис, и на этом языке уже с первого-второго курса можно зарабатывать вполне осязаемые деньги.

    Дмитрий: Тут есть аргумент, что не давать начинающим студентам некоторые вещи вроде указателей — это какое-то кощунство. У них будет огромная дыра, если человек не понимает, что, допустим, ссылка — это на самом деле всего лишь адрес переменной в памяти. Что вы думаете по этому поводу?

    Анатолий: 20 лет назад это было актуально, когда у компьютеров было недостаточно памяти, не хватало дисков и прочего. А сейчас посмотри на этих джаваскриптеров, они на каждый «hello world» притаскивают по 500 мегабайт библиотек. Сколько они занимают в памяти? Какая у них производительность? Какие там ссылки? Да никого это не волнует. Главное — это быстренько набацать и выпустить что-то в продакшн. Я не утверждаю, что это хороший или правильный путь, я утверждаю, что нужно меняться вместе с реалиями. Может быть, сейчас уже не настолько важно, сколько у тебя занимает ссылка.

    Сергей: Наверное, смотря где. Дмитрий, насколько понимаю, интересовался алгоритмическим трейдингом — живо представляю, как он подтягивает библиотеки на JS, чтобы отправить заказ на биржу.

    Дмитрий: Ну да, естественно, на практике там никто не использует языки такого типа. Хотя теоретически это, может, и возможно: не будем забывать, что в инфраструктуру JS вбрасываются неслабые деньги. Движки, которые делают компиляцию JS во всё и вся. Многие рассматривают этот язык как first-class language для всего вообще.

    Естественно, что алготрейдинг — это сейчас удалённая от подобного дисциплина, но алготрейдинг и в целом финансовая математика — это вообще специфичная область. В ней как раз преобладает C++. И преобладает он отчасти из-за инертности, просто из-за исторических причин: в начале все были на С++, а область эта консервативная.

    Сергей: Не соглашусь. Я сейчас работаю в финтехе, и коллеги, которые тут с самого начала алготрейдинга, рассказывают про крупные компании, которые сначала писали на Java. Поначалу Java справлялась с алготрейдингом, но, когда рынок стал расти и появились конкуренты с C++, они в какой-то момент просто не справились, не успели всё сделать эффективно… Так что не все в алготрейдинге начинали с C++. Просто те, кто не писал на нём, умерли. Такой естественный отбор.

    Дмитрий: На самом деле можно брать шире. Известно очень много примеров, когда даже крупные банки держат свои алгоритмы в экселевском документе. Они потом используют Excel ещё и как сервер, чтобы всё это обсчитывать. Там адские тормоза, но всё зависит от того, делаешь ли ты high-frequency trading (или вообще что-то высокочастотное). Если ты market maker — естественно, что тебе нужна высокая производительность, и там дело даже не ограничивается С++, там мы уходим в железо и HDL-языки.

    Но наша дискуссия не только вокруг алготрейдинга, а вокруг простых вещей тоже. Вот я приведу такой пример. Мне нужно было в связи со строительством написать несколько маленьких приложений, рассчитывающих разные вещи: например, как класть кирпичи вокруг контура дома. И я практически не представляю себе, как делать такие вещи на C++, потому что всё, что связано с UI, там слабее. Есть всего один фреймворк, Qt, и даже на нём писать очень тяжело. А если я сажусь за C#, за WinForms, то просто моментально делаю приложение.

    Анатолий: Ну, визуальная часть всегда являлась сильной стороной C#. Microsoft много вкладывался и в формочки, и даже в кроссплатформенные формочки, и в целом в визуализацию. Поэтому, если мы говорим о визуальных десктопных приложениях, то мне кажется, плюсы вообще далеко-далеко позади.

    Сергей: Ну, it depends, как всегда. Я UI очень не люблю, но на плюсах мне постоянно приходится его делать. Казалось бы, притащи JS и просто взаимодействуй с плюсами. Но я работал с embedded, и там это тяжело. Люди покупали какой-то быстрый дорогой движок, но он всё равно не справлялся с нормальным рендерингом UI, написанного на JS. А переписав всё это на Qt, получалось разогнать. Обыкновенная история.



    Кроссплатформенность vs кроссплатформенность


    Сергей: Я тут хотел уточнить. Я про C# мало знаю, сам трогал его очень давно, в самых первых версиях (мне тогда ещё обратную совместимость сломали). Поэтому вопрос: а его до сих пор развивает только Microsoft?

    Анатолий: Нет, сейчас он кроссплатформенный, открыт и заверифицирован под ISO (ECMA-334 и ISO/IEC 23270). Кстати, насколько знаю, у С++ до сих пор нет открытой ISO-спецификации, только платная. А C#, в отличие от этого, полностью открытый. Развивается многими компаниями (в их числе Google, Amazon и Samsung), у нас есть .NET Foundation. Я даже не знаю сейчас более открытого языка, чем С# и платформа его .NET.

    Сергей: Ну, Haskell.

    Анатолий: Кстати, автор Haskell работает в Microsoft Research и приложил немало усилий, чтобы в C# появились всякие клёвые штуки — например, статическая проверка, какая-нибудь рефлексия, о чём плюсы, вероятно, и мечтать не могут.

    Сергей: Мечтать-то могут, и даже идёт работа в эту сторону. Но понятно, что у всего есть своя цена. В C++ просто отказываются платить эту цену.

    Анатолий: Какую? Они компилируются по два часа, какая ещё может быть цена?

    Сергей: В C++ принцип zero cost abstraction. Ну то есть виртуальная машина — это не zero cost abstraction, правильно? Приходится с этим мириться.

    Дмитрий: Ну, зато виртуальная машина может, например, затюнить код для той или иной архитектуры. В то время как на С++, если использую AVX-инструкцию на компьютере без AVX, у меня процесс просто накрывается. Я бы сказал, что этот аргумент не совсем корректен, потому что теоретически — я подчеркну, теоретически — JIT может делать то, что C++ недоступно. А именно оптимизацию в момент запуска.

    Сергей: Но в C++ во время компиляции ты можешь полностью контролировать, какие инструкции тебе нужны. В данном случае не руками управляешь, а инструменту (компилятору) отдаёшь на откуп. Вот смотри, какие инструкции есть на этой архитектуре, какой набор инструкций…

    Дмитрий: Это понятно. Но можно сформулировать так: поскольку платформ миллион, мы никогда не получим какой-то идеал, потому что мы не можем релизить миллион версий с разными компиляционными флагами. Правильно? Мы выпускаем обычно x86 и x64, а не разбиваем всё это на какие-то подгруппы.

    Сергей: Почему не можем? XXI век. Держи Docker с разными параметрами, и всё.

    Дмитрий: Когда у нас есть конечный клиент, который скачивает наше приложение, он хочет скачать конкретный бинарник. И в этом бинарнике лучшее, что мы можем сделать — это натыкать везде if. Типа «if cpuid такой-то и поддержка avx такая-то, тогда используем версию алгоритма 25». В результате нам нужно 25 разных версий одного и того же алгоритма, потому что ускорение зависит от платформ, оно platform-dependent.

    Сергей: Наверное, согласен. Просто я, если честно, ни разу не создавал не-внутренний продукт. Я в основном в компаниях, которые сами используют свой продукт.

    Дмитрий: Ну, конечно, самый лучший вариант, когда ты предсказуемо знаешь архитектуру. В этом случае, строго говоря, вообще никто не заставляет тебя использовать x86-инструкции. Можешь брать конкретную карточку (например, Nvidia Tesla) и делать всё, что хочешь. Это и мой подход тоже, я контролирую свою архитектуру. Но когда ты делаешь mass-market решения для пользователя… Если взять какой-нибудь условный ReSharper, он не может просто взять и использовать GPU-ускорение для каких-нибудь произвольных индексов. Потому что GPU-ускорение — это не портативная штука.

    Сергей: На самом деле есть подходы (сейчас в детали, наверное, вдаваться не нужно), есть интересные ребята (автор подхода, кажется, сейчас тоже в Microsoft перешёл). Вот у нас на конференции в позапрошлом году был доклад про то, как бы написать такую программу, которая сама будет разбираться, что где (относительно легко, опять же zero cost abstractions). Чтобы на лету можно было выбирать, и если что, грамотно перестраивать код в CUDA-стиль…

    Дмитрий: На самом деле CUDA сама пытается решить эту проблему, потому что в CUDA есть некий промежуточный слой PTX, который этим занимается. Но это пока всё очень тяжело, потому что железо кардинально меняется эволюционно, и очень сложно за этим вообще поспевать. И если мы посмотрим на использование GPU-ускорения, например, в продуктах Adobe, то они используют очень узкий срез имеющихся технологий. Если у тебя карточка правильная — то да, всё будет. Но если она чуть-чуть экзотическая — в этом плане уже не гарантировано ничего.

    Анатолий: В этой дискуссии мы затронули довольно важную тему, такой миф: C++ декларировался много лет назад как такой кроссплатформенный язык, но на данный момент кроссплатформенности куда больше в C#. Один-единственный бинарник, работает везде, где поддерживается .NET, а это практически везде.

    Сергей: Ну, это тоже достаточно голословно. Я как человек, большую часть жизни проведший в embedded, редко видел, чтобы .NET поддерживался тулчейном производителя железа. Компании, которые производят железо, берут тот же G++ или Clang или делают так, чтобы он начинал генерировать код для их платформы.

    Дмитрий: Да, но проблема в том, что каждый раз, когда они это делают, они теряют что-то из С++. Например, Nokia использовала вариацию C++, но их C++ был с безумными наворотами и безумным API, которое всех бесило. То есть это не просто С++, а С++ под ту или иную платформу. И тогда начинаются проблемы. Например, взять ту же CUDA. Она как бы должна плюсы просто через себя пропускать, она вообще не компилятор, а просто драйвер. Но несмотря на это, у неё бывают затыки с тем, что она всё-таки использует какой-то фреймворк для раздирания CUDA-файлов на GPU- и CPU-части. И иногда у неё это не получается.

    Сергей: Я немножко не это имел в виду. Просто, когда я слышу, что «.NET везде запускается», большая часть моей рабочей биографии взбрыкивается. Когда ты покупаешь железку с кастомным процессором, она просто идёт в комплекте с поставкой G++. И там обыкновенный C++, который G++ из тулчейна умеет преобразовывать в машинный код, поддерживаемый именно этим процессором.

    Дмитрий: Но это опять надо пересобирать…

    Сергей: Конечно.

    Дмитрий: И идея, что мы берём уже существующий плюсовый код и втаскиваем его на железку — эта идея тоже не работает, потому что внезапно ты втащил свой обычный x86 куда-то, где у тебя 8 гигабайт памяти на всё про всё, и уже не развернуться: например, нет свопа на диск, потому что нет диска и доступа к нему. Это если мы про портативность. Зависит от целей, естественно.

    Анатолий: Плюсы работают на большем количестве устройств, и, безусловно, embedded — это одна из сильнейших частей. Но обычно придётся как-то под платформу свой код адаптировать. Вот это плохо. Я могу одним кодом накрыть огромное число платформ, архитектур, моделей. На плюсах мне приходилось думать о каждой отдельной платформе: а где он там запустится, а при каких условиях. И это очень плохо, это очень сдерживает.



    Стабильность, совместимость, развитие языка


    Дмитрий: Ещё были упомянуты zero cost abstractions, но проблема в том, что у этого огромная цена. Например, в .NET есть понятие перечисляемого типа и интерфейс IEnumerable. И у каждого типа, например, массива, можно взять и проходить по итератору. А в C++ такой идеи нет. Из-за zero cost abstraction, чтобы обойти коллекцию, есть пара begin() и end(), есть правила их работы, и всё это намного сложнее (особенно для тех, кто начинает программировать). Это прямо проблема: как обойти какой-нибудь массив «от А до Я».

    Сергей: Если я правильно понимаю, о чём вы говорите… Если просто нужно обойти какой-то контейнер от начала до конца, то сейчас просто пишешь, как в каком-нибудь Питоне.

    Дмитрий: Это всё прекрасно. Но у тебя, например, нет использования полиморфизма для этого. Ты не можешь сказать, что вот у меня функция, которая получает некое значение, которое является перечисляемым априори. Ты не можешь сказать, что вот у меня есть значение, которое реализует интерфейс, и вот в этом интерфейсе есть итератор, например.

    Сергей: Мы говорим про какой C++? Про C++ вообще, C++ будущего, С++, который сейчас принимают в стандарт?

    Дмитрий: Ну, если в плюсах будущего это будет…

    Сергей: В C++20 это уже есть. Уже можно сказать, уже можно самому даже объявлять. Это не интерфейсы, но, как правильно сказать… В общем, можешь объявить, что у тебя тип должен удовлетворять таким-то условиям. Например, у него begin и end, которые возвращают итератор. А итератор — это в стандартной библиотеке такой подготовленный концепт. Он говорит, что это такое, описывает. Итераторы тоже разные бывают. В общем, стараемся, делаем так, чтобы людям было удобнее.

    Дмитрий: Мне кажется, это выросло из того, что люди просто поняли, что без концепций итерируемости объекта жить тяжело. Потому что непонятно, как писать обобщённые вещи. Да, zero cost abstraction означает, что у нас нет затрат на хождение по v-table при поиске… В .NET есть просто конкретный метод, например. И нам, чтобы его найти, естественно, приходится затратить усилия, от которых плюсы отказываются. Но с точки зрения юзабельности всё-таки конечный результат не такой хороший, я бы сказал.

    Сергей: Естественно, должен быть баланс. Нельзя иметь всё и сразу.

    Анатолий: Это заставляет задуматься: сколько лет прошло. Альтернативные языки развиваются, и в них такие базовые вещи появляются с самого начала. Сейчас они догоняют что-то более существенное и интересное. А плюсовики сидят по десять лет с одним и тем же непонятным синтаксисом, непонятными абстракциями, непонятными костылями и слабо развиваются. Можно это поставить как один из минусов.

    Сергей: Ну come on! Что значит «слабо развивается»?

    Ты упоминал комитет — у C++ тоже есть комитет ISO, который его развивает. Там есть представители в том числе Microsoft, которые сильно топят за то, что «нельзя такое делать, потому что у нас куча легаси, которое нам надо поддерживать». Просто C++ — это язык уже состоявшийся. И, естественно, очень аккуратно шагает. Одна из главных задач (что было декларировано ещё Страуструпом при создании) — это совместимость с C. Но сейчас C уже даже развился достаточно далеко, приходится обозначать, с каким именно C совместимость.

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

    Анатолий: Кажется, что все эти метаклассы, итераторы — это реально вдохновение, которое было уже много десятков лет назад. Даже если метапрограммирование взять, шаблоны, макросы — это же всё люди давно пережили, перемололи, и существуют намного более простые, очевидные, понятные концепции. В других языках это всё сделано в миллион раз лучше и быстрее, с типобезопасностью, проверкой в compile time и так далее.

    Сергей: Подожди, ты уже говоришь про то, за что не все готовы платить. Я не хочу, чтобы моя программа что-то проверяла в compile time без моего ведома. Понимаешь?

    Анатолий: Я думаю, это всё флажочками можно настроить. Уровень оптимизации ставишь, и она тебе или проверяет, или нет. Это не проблема.

    Сергей: Часто нужно контролировать всё руками. Точно знать, что происходит. Потому что инструменты — ну такое.

    Дмитрий: Тут даже не про инструменты. Тут тот факт, что языки вроде D и Rust, допустим, говорят: ну вот да, есть такая фишка, что когда доступ к элементу массива, можно его проверять, а можно не проверять. И они просто отдают это на откуп пользователя, то есть ты можешь сказать «а давайте отключим проверки массивов», «а давайте включим». То есть контроль какой-то в этом плане.

    Сергей: Непонятно тогда, когда у тебя Unsafe и Safe есть, как в Rust, я не вижу разницы с C, например, в таком случае.

    Анатолий: Разница в том, что ты можешь писать безопасно, а можешь писать быстро. А в C ты вынужден писать опасно. Ну, да, может быть, быстро. Иногда намного важнее стабильность продукта, чем быстрота.

    Дмитрий: На самом деле, если уж мы начнём копать вот тему с новыми языками, в С++ есть такие вещи, которые вообще очень тяжело донести до людей. Простой вопрос: какого размера int? В большинстве языков ты знаешь ответ на этот вопрос. Ты говоришь: int — это 32 бита. А в плюсах не знаешь. Ты знаешь размер на своём конкретном компьютере, потому что запомнил, но, строго говоря, даже базовые типы не хочется использовать, потому что они недетерминированные. И вот меня бесят такие вещи, когда есть набор легаси-подходов вроде того, что int будет разным на разных платформах. И сейчас-то мы уже понимаем, что так делать нельзя. Почему бы не шагнуть дальше этого и как-то решить эту проблему?

    Сергей: Ну, это решено. Есть STD, нужные типы с фиксированной длиной. Сейчас представитель России в комитете втаскивает int переменной длины (ну опять же, с zero cost abstraction).

    Анатолий: А я правильно помню, что там даже недетерминированный размер указателя на метод? То есть под разные компиляторы и разные платформы указатели разные?

    Сергей: Естественно, это архитектура. Когда ты близко к железу, как ты можешь гарантировать размер указателя, если ты то на 8-битной, то на 64-битной?

    Анатолий: И как можно после этого какую-то арифметику на указателях делать? Это же с ума сойти.

    Сергей: В смысле? Ну, аккуратно.

    Анатолий: Понятно. Подход везде понятен, аккуратно, ручками контролируя всё.

    Сергей: Ну да. Опять же, в современных стандартах C++ развиты подходы… Если говорить о выборе, то в современных плюсах, по сути, есть выбор, использовать ли сборщик мусора. Просто GC там построен на reference counter-ах.

    Вообще, по вашим словам, коллеги, я, простите, чувствую, что вы давно не обновляли знания про современные плюсы.

    Сейчас от людей вроде Страуструпа, входящих в пантеон плюсовых богов, исходит много призывов разобраться с тем, как преподавать современный C++. Проблема в том, что люди думают в категориях C++ 2003 года, и преподают в этих же категориях. И в связи с этим есть интересные новые проекты и подходы, есть современные курсы — скажем, ребята из Яндекса сделали прекрасный курс. И сейчас в плюсах считается моветоном, например, использовать чистые new и delete.

    Дмитрий: Насчёт твоего комментария про обновление знаний… Нюанс в том, что мой подход, например — использовать маленькую дельту C++, которая у меня гарантированно работает и с которой я «дружу». Понимаешь, C++ обширен. Есть шаблонное метапрограммирование, и всё бы хорошо, там много магии, но, к сожалению, эта магия нечитабельная. Это код, в котором не-автору без каких-то особых знаний не разобраться, в каком-то смысле чёрный ящик. И вот таких чёрных ящиков в плюсах много, таких областей тьмы, которые не переварить… Хочется, чтобы, не знаю, твой опцион обсчитывался предсказуемо, хорошо и без каких-либо ухищрений.

    Самый простой пример — разговор про ranges (range-v3 и вся эта тема). С одной стороны, всё это здорово: появляются вещи, которые в C# уже были несколько лет, позволяющие, например, построить календарик путём всяких преобразований стандартной коллекции. С другой стороны, то, как это реализовано в С++, просто неприятно по сравнению с C#: оно тяжело, неудобочитаемо.

    Сергей: Это вкусовщина. Мне, наоборот, нравится. Я так понимаю, ты к докладу Ниблера и его представлению…

    Дмитрий: Понимаешь, когда для фильтрации коллекции используется оператор «или», у меня сразу к этому вопросы. И C#, и Java всё сделали через точку, через обычные методы.

    Сергей: А мне кажется, это вдохновлено Bash'ем. То есть это просто pipe.

    Дмитрий: Ну, да, наверное, это объясняет что-то в этом подходе.

    Сергей: Многое объясняет! Давайте вот про PowerShell поговорим, раз заговорили про Bash. Кто видел PowerShell?

    Анатолий: Я пишу на PowerShell, шикарный язык. Но опять же, pipe нужно вставлять там, где он к месту, там, где вся архитектура им пронизана. Не там, где тебе нужно сделать какое-то одно действие, и оно здесь идиоматически плохой синтаксис.

    Сергей: В range'ах pipe как раз очень…

    Дмитрий: В range они используются, по-моему, по следующей причине… Скажу так: если бы в C++ были extension-методы или extension-функции, использовали бы их, конечно. Потому что самое естественное, если вам нужно отсортировать коллекцию — это написать «коллекция.фильтр()». А не «коллекция | view:: фильтр()».

    Анатолий: У меня тоже сложилось такое впечатление, что тебе 20 лет стреляли в ноги, били по лицу, стучали головой о стену, а потом в конце концов говорят: «Ну вот мы теперь всё сделали красиво в 20-м стандарте, давайте теперь учить плюсы правильно». Да уже никто не хочет их учить правильно! То есть это боль многолетняя.

    Сергей: Пожалуйста, не учите. В чём проблема? Пишите на C# — торгуйте на нём, пишите embedded. Я не против.

    Анатолий: Ну, есть узкие ниши, где плюсы всё ещё остались.

    Сергей: Embedded — «узкая ниша»… Я прямо сейчас, глядя у себя на кухне по сторонам, вижу кучу компьютеров.

    Дмитрий: Я каждый раз, когда лечу на самолёте, думаю: «Блин, надеюсь, эти плюсовики хорошо всё там написали».

    Сергей: Ну, кстати, там в основном Ada, насколько я помню.

    Дмитрий: Ada там доминирует, да.

    Анатолий: Мне, кстати, недавно попалась отличная статейка, где автор на разных языках (около 10) написал низкоуровневый драйвер — network driver для 10-гигабитной карточки Intel. От C до Swift, JS, Python и, естественно, C#. Если мы посмотрим на эти графики, которые у него получились, то C# на больших батчах (когда нивелируются расходы на запуск) идёт вровень с C и Rust.



    То есть, если мы говорим о производительности, может быть заблуждением, что C# очень сильно где-то уступает. Есть ещё обалденный доклад Федерико Луиса Scratched Metal, где он показывал, как оптимизировал C#-код под процессорные профайлеры.

    Сергей: Ну это опять начинается. Штука в том, что когда ты начинаешь оптимизировать что Java, что C#, становится непонятно, почему не писать на плюсах. Потому что тебе нужны специфичные знания. И, как мне кажется, нивелируется преимущество языков вроде C# и Java — не очень высокий порог входа. Насколько понимаю, как раз то, про что Дмитрий говорил: про читаемость кода, что учить много, тяжело объяснять какие-то концепции и так далее.

    Анатолий: Я на работе 99% времени пишу на «нормальном» С# — безопасном, стабильном и всё время работающем. А 1% времени я хочу написать какой-то быстрый низкоуровневый код. И это C# мне тоже позволяет. Но основной мой инструмент — это всё-таки стабильный, читабельный, без ошибок…

    Дмитрий: Толя, давай я приведу тебе простой пример: векторизация. С векторизацией в .NET всё очень плохо, несмотря на то, что медленно пилится System.Numerics.Vectors. И к чему это приводит, с моей стороны, например? К тому, что если суёшься на рынок и покупаешь математическую библиотечку для .NET, она написана на плюсах (с дотнетной обёрточкой). Потому что в .NET нет практически никакого доступа к аппаратному ускорению (AVX и прочее), это сейчас на каком-то зачаточном этапе.

    Анатолий: В .NET Core 3 вышли интринсики, где можно напрямую обращаться к AVX. Они там действительно в зачаточном состоянии, но базовые вещи есть, а остальное вполне двигается.

    Дмитрий: Ты понимаешь, у нас 2019 год на дворе. Я как пользователь всего этого математического ускоренного добра не дождался этого. И в результате для меня, если хочу что-то быстро считать, C# уже не кандидат. Потому что библиотеки на C++ уже есть. Может, уже время упущено для этого.

    Анатолий: Мне кажется, что C# движется в сторону плюсов, он пытается отвоевать их рынок. А вот плюсы уже не движутся никуда.

    Сергей: Откуда это? Что значит «плюсы не движутся никуда»?

    Анатолий: Когда мне в 2019 году рассказывают, что в будут стандарте будут итераторы, будут какие-то подвижки насчёт лямбд, мне кажется, что…

    Сергей: Я не знаю, зачем ты разговариваешь про итераторы и лямбды, не понял, в чью сторону был камень…

    Анатолий: Не про итераторы, я неправильно выразился, я имел в виду enumerable'ные контейнеры, которые мы до этого обсуждали. А у нас тем временем появился pattern matching.

    Сергей: Всё зависит от того, надо это или нет. У нас pattern matching обсуждают. Но пока нет всех аргументов, нужен ли он именно в плюсах.

    Дмитрий: Я слышу много подобных комментариев от плюсовиков, которые говорят, что «хотя уже есть очевидное присутствие того или иного подхода в других языках, он уже отработан, люди его любят и строят на нём решения, мы всё равно не хотим это в плюсах, потому что это не идиоматично плюсам». И мне кажется, что Java попала в ту же дыру. Java сказала «нет, ребята, у нас делегатов не будет». И в Java до сих пор нет понятия делегатов, а в .NET всё это прекрасно работает.

    Сергей: Смотри, в плюсах всё очень просто. Опять же, возвращаемся к комитету. Там есть верхушка — это люди, которые занимаются разработкой компиляторов. И для них слова «zero cost abstraction» — это как раз то, чем они должны руководствоваться. И словом «legacy», к сожалению.

    Дмитрий: Ну, zero cost abstraction — это ассемблер. Если мы хотим вообще zero cost abstraction, надо писать всё на ассемблере.

    Сергей: Там нет abstraction.

    Дмитрий: Ассемблер — это абстракция над бинарным кодом. Просто это второе поколение, а не третье.

    Сергей: Так вот, про всякие «удобные штуки» оказывается, что непонятно, как заставить их быстро работать.

    Дмитрий: Пускай они работают медленнее. Идея с асинхронными итераторами, корутины, всё вот это — в .NET с C# ключевое слово yield уже не знаю сколько релизов прекрасно работает. Да, за кулисами строятся огромные стейт-машины, прям магия. Но и в async/await строится магия, и в итераторах. Но все этим пользуются, и это реально удобно.

    Сергей: Корутины и в плюсы добавляют, здравствуйте.

    Дмитрий: Ну да, прогресс идёт. Но корутины появляются сейчас, а не 10 лет назад.

    Сергей: Ещё раз. Плюсы старше, и на мой взгляд, скорость развития падает с накоплением кодовой базы. Понятно, всё зависит от того, есть ли желание сохранять поддержку легаси. Для плюсов это принципиальная позиция. То есть код, который ты написал в 80-х, сейчас скомпилируешь современным компилятором.

    Дмитрий: Да, но код, который ты написал на C# 1.0, ты тоже скомпилируешь современным компилятором.

    Сергей: Это неправда. Я в самом начале дискуссии сказал, что у меня на ранних версиях .NET прилетело обновление, и внезапно все программы перестали работать.

    Дмитрий: Возможно, просто поменялось API, которые ты использовал. Тут нужно разделять библиотеки и язык программирования.

    Сергей: У меня ничего не было, просто C#. Я был молодой, это были первые годы.

    Дмитрий: Я помню только один breaking change, в C# 4 — изменение поведения foreach чуть-чуть. Конечно, в версиях 1.x всё могло быть более турбулентно, но сейчас мы точно не в такой фазе, когда кто-то что-то внезапно ломает.

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

    Дмитрий: В общем, в .NET тоже следят за обратной совместимостью, но скорость прогресса обскакала и C++, и Java.

    Сергей: Мне кажется, сыграло большую роль, что вначале всё это драйвила одна компания. Потому что C++ изначально в комитете — а это политика, каждый пытается протащить своё решение, и это как заседание Сената в «Звёздных войнах».

    Дмитрий: То есть твой аргумент в том, что мы все заложники комитетов, которыми движет не инновация?

    Сергей: Проблема в том, что не выбрать решение, которое удовлетворит всех. Инструмент настолько широко разошёлся, что его использует очень много компаний. Ты те же корутины вспомнил: почему их приняли поздно? Потому что Microsoft, кажется, с Google не мог договориться. Были две имплементации — я не помню, кто был за stackful, а кто за stackless, но не могли договориться. Потому что обе компании большие, у них огромные кодовые базы, которые уже содержат решение, и они отказываются это переписывать.

    Дмитрий: С точки зрения читателя создастся ощущение, что на него плевали с высокой колокольни, потому что есть corporate interests, они занимаются там междусобойчиками, а вас всё это как бы и не касается — идите, холопы, «let them eat cake».

    Сергей: Всё как раз наоборот. Комитет пытается выбрать так, чтобы обыкновенному человеку не пришлось страдать. И часто это тяжело.

    Дмитрий: Ну, я за себя могу сказать, что не буду страдать, если где-то пропадёт прям zero cost, зато появится какая-нибудь гибкая возможность ходить по бинарному дереву и делать итерирование разными способами без временных переменных. Если внезапно появилось ключевое слово yield, которое за собой тащит стейт-машину или ещё что-то — я готов на это, потому что знаю, что выигрыш от этого будет больше, чем то, что я теряю на каких-то микросекундах.

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

    Сергей: Если ты хочешь выбор, у тебя есть Boost.

    Дмитрий: Нуу, как сказать. Boost используется, хорошо, что он есть, но… Мы всё-таки в первую очередь смотрим на инструментарий из коробочки. Даётся мне тип std::string, я смотрю, что в нём есть. Там есть и size(), и length(), и у меня уже когнитивный диссонанс: зачем два, почему нельзя было что-то одно задепрекейтить? И тут появляется кто-то и говорит, что у нас легаси, мы уже не можем назад. Это немножко грустно, конечно. И это, мне кажется, вопрос, где мы никогда не найдём золотой середины. Потому что если отталкиваться от того, что нельзя ломать язык, то в нём остаётся много довольно безумных вещей, которыми обязательно кто-то будет пользоваться.



    Компиляция


    Дмитрий: Давайте немножко отойдём от этой темы и поговорим про другие насущные проблемы, например, такую, как банальная скорость компиляции. Что вы можете сказать по этому поводу?

    Анатолий: У меня осталось впечатление от плюсов, что, когда я нажимал на кнопочку «компилироваться», сразу шёл заваривать чай.

    Сергей: Всякое бывает.

    Анатолий: И даже на embedded-устройствах, там тоже можно закрутить кучу include, миллион макросов?

    Сергей: Ну это от архитектуры компиляции не зависит. Мы на embedded обычно кросс-компилируем.

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

    Дмитрий: Сокращается постепенно. Раньше было 150 мегабайт. Сейчас можно как-то нарезать всё это на кусочки, это долгая дискуссия. Становится лучше.

    Сергей: Я могу и про плюсы сказать, что всё становится лучше!

    Дмитрий: Сейчас компьютерная игра, которую ты покупаешь в Steam, весит, например, 64 гигабайта. Скажи, тут 150 мегабайт погоду сделают?

    Сергей: Ну, наверное, нет.

    Анатолий: И компиляция у тебя происходит каждую минуту, а деплоишь ты свой продукт раз в неделю-две. Зачем оптимизировать время деплоя на уровне компиляции каждую минуту? Я хочу компилировать очень быстро, а потом, когда буду собирать под конкретную платформу, тогда да — пусть оптимизирует, вставляет свои оптимальные zero cost abstractions и прочее. Но зачем мне это платить каждую секунду-то?

    Сергей: Я не очень понял про каждую секунду, мне кажется, как раз в дотнете платишь каждую секунду, как используешь приложение, нет?

    Анатолий: Я имею в виду, что компиляция должна быть быстрой. Она не должна быть максимально оптимизирована, она должна быть быстрой, чтобы было комфортно разрабатывать.

    Сергей: Ну, мы опять просто приходим к тому, что я могу сказать, что это легаси. У плюсов медленная компиляция — да, я с этим не спорю. Сейчас есть более прагматичные подходы, а плюсовый морально устарел. Но сделать с этим сейчас, не ломая ничего, очень сложно. Ну вот будут теперь модули, я надеюсь. Много проблем с легаси-кодом. А это всё растёт из C.

    Дмитрий: Это очередная проблема. Есть у нас подход типа «модули». И я бы со своей колокольни сказал: ребята, мы переходим на модули и макросы больше не будут поддерживаться вообще никак. Более того, давайте со следующей версии, если включаешь модули, то отключаются макросы глобально везде. Вот это был бы мой подход. К сожалению, никто о таких кардинальных шагах не думает.

    Сергей: Почему, о них думают. Но их не поддерживает комитет. Наверное, есть причины. Но я тебе предлагаю сделать proposal. Это же открытое всё.

    Дмитрий: Мы же понимаем, что это обречённый proposal. И обречён он по той причине, что никто не хочет внезапно сказать «надо переписывать»: допустим, в STL используются макросы, надо от них избавиться. Нужно, чтобы кто-то сделал волевое решение, сел и избавился от всех макросов.

    Сергей: STL как раз не проблема по причине маленького размера. STL переписывают часто. Не знаю, хорошо это или плохо, но недавно STL переделали — много изменений, которые не заметны снаружи, но внутренняя логика у них поменялась.

    Дмитрий: Ну видишь, а остальное — почему нельзя сказать, что остальное в топку? Если хотите модули, то у вас только greenfield. Мы не делаем brownfield development, только новые проекты. Новые проекты — значит, только модули. Старые проекты — без модулей. Нельзя так сделать?

    Сергей: Комитет считает, что нельзя. Есть такие разговоры, но по сути, так работают экспериментальные версии. Не так радикально, что насовсем отключение. С модулями проблема именно с макросами, как правильно говоришь, и каждый топит за своё. G++ за своё, Clang за своё. Цена представительной демократии.

    Дмитрий: Но тут, видишь, никто просто не допускает возможности того, что решение может быть радикальным. Сказать «последующие версии будут устроены так, что либо A, либо B». Для меня как для человека, который часть времени проводит в .NET, идея втаскивания макросов в модули безумна по своей сути. По аналогии, вместо того, чтобы втаскивать их в модули, вместо этого почему бы не сделать отдельные текстовые файлики, засунуть все экспортируемые макросы туда и сказать, что на этом как бы и всё?

    Сергей: Потому что, по сути, ты предлагаешь делать новый язык. Согласись, это уже будет C++ 2.0. Или ++C++. Он будет относиться к плюсам так, как они относятся к C.

    Дмитрий: Ну нет, я тут не соглашусь. Потому что мы тут в конечном счёте не обсуждаем язык, мы обсуждаем компиляторы, технологию компиляции. То, что там, может, и применяются инструкции, вместо #include будет #import или что-то в этом духе — это всё второстепенно. Мы обсуждаем, что у компилятора внезапно появится своё мнение насчёт вот этой проблемы. И, судя по всему, никто не хочет сказать, что давайте будет компилятор с особым мнением насчёт макросов в модулях, допустим.

    Наше время подошло к концу. Если читателям окажется интересно, можно будет потом устроить ещё одну дискуссию. А пока предлагаю вам, коллеги, сказать небольшое завершающее слово на тему того, как вы видите ситуацию в C# и C++, что вы видите в будущем и какое у вас впечатление от сегодняшней дискуссии.

    Анатолий: У меня укрепилось впечатление, что в плюсах сейчас занимаются вещами, которые должны были появиться 10 лет назад. Это всё происходит очень медленно, очень тяжело, и не факт, что будет в том виде, в котором должно быть, потому что обычно реализуется всё очень многословно, неудобно для программиста. И всё это можно свести к легаси и «исторически сложилось», но конечному программисту на это наплевать. Он хочет получать удовольствие от работы, и на плюсах сейчас получать удовольствие очень сложно.

    C# разрабатывался, чтобы легко было переходить с C++. Если знаете плюсы, то вам переходить на C# не составляет никаких проблем совершенно. Но вы забываете практически о всех проблемах, самое плохое выбрасываете, оставляете самое хорошее. И у вас появляется новый язык, новая платформа, динамически развивающийся понятный программный комитет, компиляторы, новые JIT'ы — всё то, чем можно гордиться, радоваться каждый день новостям и не заботиться о каких-то грубых мелочах (какой у вас размер int). Мне кажется, выбор должен быть довольно очевиден, особенно для студентов, которые только задумываются о том, какой бы язык выучить.

    Сергей: Ну, по тому, что я услышал, программистам на C# нечем гордиться непосредственно в своей работе — приходится гордиться работой программного комитета. Мне кажется, это как раз объясняет, почему на C++ приятно писать. Это сложно, и ты всегда видишь результат. Плюсы (по тому, что я знаю) — это обычно cutting edge. Как мы правильно говорили, не будет человек делать UI-приложение на C++, сейчас это просто не та ниша, где они нужны. А на C# — пожалуйста. На C++ ты пишешь код, который быстро работает.

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

    Ну и у меня так и не получилось понять, насколько C# кроссплатформенный и независимый от Microsoft. Несмотря на то, что говорили о .NET Foundation, всё время все разговоры про то, кто что делает, были про Microsoft. Не совсем понятно, насколько хочется складывать все яйца в одну корзину и зависеть от одной компании.



    Пост создан при поддержке конференций C++ Russia и DotNext. Напоследок опрос: а что поддерживаете вы?

    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

    За какую сторону вы?

    • 27,7%C++280
    • 36,2%C#366
    • 10,0%Ни то, ни другое101
    • 26,1%Дискуссии «какой язык лучше» — это ***264
    JUG Ru Group
    Конференции для программистов и сочувствующих. 18+

    Комментарии 415

      +24
      На C++ ты пишешь код, который быстро работает.

      Достаточно спорно, вернее это совсем не так. Подобные утверждения создают путаницу и только вредят C++, да и объективности как таковой. Правильно говорить, что на C++ ты можешь написать код, который быстро работает. А вот на дотнете не всегда. Дизайн языка/язык в общем виде, как и уровень его пользователей, определяют тот набор возможностей(и от языка, который даёт возможности. И от программиста, который хочет и может использовать). И уже это вкупе даёт ту самую производительность.

      Если программист не знает как пользоваться возможностями, либо знает, а язык не позволяет — ничего не получится. И C++(современный) хоть и даёт практически безграничные возможности(относительно, конечно), но первую часть тезиса никто не отменял.

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

      И это чистая правда. Причём это сложно донести не только людям со стороны, но и множеству программистов на самом C++.
        –3
        мда… утверждать что Шарп лучше потому что на нём мордочки можно быстрее рисовать чем на тролтеховской куте и они красивее получаются… я в 2005-2010 гг. рисовал в борландовском билдере такие, что и сейчас не всегда получаются. с ворованными девелоперекспрессовскими компонентами, с наборами джедивцл, фастрепортом это было просто, быстро и красиво. но как можно приравнивать мордочки и качество языка?
          +4

          Ну, честно говоря, если уж писать "наскоро" GUI на Qt, то я бы стал писать его на Qt Quick, а не на плюсовых виджетах, а к этому GUI на Qt Quick уже подключать какую-то "рабочую" логику уже на плюсах, благо делается это элементарно. У меня был небольшой опыт написания гуя и на C# (WPF+XAML), и мне Qt Quick понравился больше.

            0
            Ну, спорное заявление..)) Ооочень спорное.
              +2
              Ну, я про себя пишу. Для меня, например, вопрос возможности переиспользования одного и того же кода и на десктопе и на мобилках довольно важен. Qt мне такую возможность в значительной степени обеспечивает и на Windows, и на Linux с MacOS, и на почившем в бозе Windows Phone, и на Android с iOS. WPF — это только платформы MS, ну по крайней мере в свое время так было, может, сейчас с этим получше, но в одном из соседних обсуждений мне говорили, что лучше с этим не стало.
                –3

                Какой-нибудь Xamarin для вас тоже не вариант?


                P.S.Ну и по хорошему надо будет посмотреть что в плане кроссплатформа нам реально сможет дать .Net 5.0

                  +3

                  Ну голый Xamarin, насколько я помню, это просто обёртка из классов поверх возможностей целевой платформы, то есть, условно, для Android будет один код, для iOS — другой. Xamarin Forms вроде как облегчает этот вопрос, но… только для Android, iOS и UWP, насколько я понимаю. Linux с MacOS в пролёте.

                    0

                    Ну если вы вот прямо под все ОС пишите, то тогда C# действительно менее удобен. Как минимум на данный момент уж точно.

                      0

                      Если говорить о кроссплатформенности, то корректно говорить о .NET Core, а он работает и на Linux, и на MacOS. Но стоит упомянуть что пока кроссплатформенный WPF Microsoft не завезли (только для Windows).
                      Но если сильно хочется всё таки иметь кроссплатформенный UI (Win, Linux, MacOS), на C#, да ещё и XAML-like синтаксисом формочек, то есть, уже какое-то время, AvaloniaUI.
                      А если хочется чтобы основная кодовая база была единой для всех платформ, что для .NET Core, что для Xamarin, то для этого прямая дорога в .NET Standard library. Пишите библиотеку, и можете её подключить и использовать в любой .NET среде — NET Framework, NET Core, Xamarin, Mono (а вместе с тем и Unity3D, который может работать хоть на консоли). Таким образом C#'ом можно покрыть практически все платформы (за исключением конечно же Embedded), при этом в моих руках всё удобство и гибкость С# и тд.

                        +1
                        Практически все платформы, это полторы? ))))
                          +1
                          Мне как бы не особо интересно «написание библиотек», мне интересна такая разработка продукта, в процессе которой я мог бы переиспользовать как можно больше ВСЕГО кода продукта, в том числе UI (в идеале 100%) при переводе его с платформы на платформу. Авалонию я не пробовал, но вот здесь мне писали, что она очень сырая, да и поддержка мобильных платформ там, насколько я вижу, числится как экспериментальная.
                            –1
                            Простите, а куда вы собственно пишете всю бизнес-логику без библиотек? Прям в main()? :)
                            Если говорить про переиспользование кода, то пишется всё под .NET Standard, и переиспользуйте где хотите. По UI, AvaloniaUI покрывает десктоп (один UI на все платформы), и Xamarin Forms покрывает мобильные платформы (опять же — один UI для Android, iOS, UWP).
                            В итоге мы имеем общий код, спокойно переиспользуемый на любой платформе, плюс переиспользуемый UI (отдельно для десктопа, отдельно для мобильных платформ).
                            Касательно авалонии в частности, то не видел чтобы её рассматривали для мобильных платформ ибо позиционируется этот фреймворк как замена WPF под .NET Core. И для мобильных платформ, как я уже упоминал, есть Xamarin Forms (один проект работает для всех платформ). Насчёт «сырости» я не хочу судить, так как проект в котором я его использовал, в плане UI, был довольно ненагруженный, и текущего уровня авалонии хватает за глаза — и графики построить, и рендерить картинки любой сложности, и при этом не задумываться про платформу на которой это всё собирается.
                            Мне честно даже очень интересно какие use-case'ы пока не может покрыть C#. Как уже говорилось это разработка под Embedded платформы (сюда же микроконтроллеры), и ещё High-Performance calculations. Есть ещё какие-то варианты?
                              0
                              Ну вот я ниже в качестве примера привел ссылку на продукт, который сейчас написан на C++ и Qt, и доступен под Windows, Linux, MacOS, под которые он собирается ну практически со 100% переиспользованием кодовой базы, ну и плюс имеет «облегченный» вариант для мобилок (Android, iOS) на тех же технологиях, которые тоже шарят между собой кодовую базу. Возможно, конечно, это у вас пойдет по графе «high performance calculations» (а их там есть, это да).
                                0
                                Интересный продукт, мы чем-то похожим в университете занимались, с моделями сердца работали и ещё какими-то органами (их срезы и модели в виде облаков точек).
                                Касательно тех критериев что вы описали в том комментарии, я считаю что это можно сделать на C#, и общую кодовую базу (.NET Standard), и UI хоть под десктоп и под мобилки (AvaloniUI + XamarinForms), при этом ни на шаг не уходя от C#.
                                Тут я вижу только 2 подводных камня:
                                1. HPC — а для предложенного вами приложения это, я считаю, самый критичный момент
                                2. Движок для рендера

                                Насчёт первого, я думаю бОльшую часть можно покрыть с использованием ILGPU (буквально веткой ниже пару слов написал об этом). Не думаю что можно абсолютно всё покрыть, всё таки в шарпе ещё не всё радужно с векторизацией как хотелось бы.
                                Для второй проблемы, есть два варианта. Это использование OpenGL(OpenTK) или любой другой плюсовой библиотеки для рендеринга, ну или честный .NET вариант (таких примеров правда не видел). То бишь данный момент нас так или иначе тянет к решениям на плюсах.
                                Либо, использование Unity3D в качестве UI. При этом данный вариант решает проблему как UI кроссплатформенности вообще (один 'UI' под все платформы), так и вычислений (используя Compute Shaders, который тоже в итоге кроссплатформенный и кроссжелезный).
                                Но боюсь что Unity не подходит для «кровавого enterprise'а», хотя если сильно захотеть…
                                Звучит такое решение конечно самоуверенно, да и я не знаю какие в вашем продукте есть подводные камни, какая архитектура и тд. Но если отвечать на вопрос что можно ли такое сделать на C#, я придерживаюсь мнения что да, это возможно.
                                  0
                                  Про ILGPU я прочел, да. Но, насколько я вижу, это CUDA only, а значит, только NVIDIA. Там, вроде, стоит красная галочка напротив AMD, но красная — это значит «когда-то в будущем». Ну и там не только и не столько рендеринг, сколько именно реально тяжелые вычисления при всяких там автоматических сегментациях, например, для чего и нужны собственно CUDA и OpenCL, а также при отсутствии нужных карточек это должно делаться и на CPU, причем как можно более эффективно. Не знаю, как у C# с этим. И насколько там будут эффективны compute shaders у unity — тоже вопрос. Ну ОК.
              +1
              «А вот на дотнете не всегда.»
              — и как выглядит это «не всегда», мне интересно?
              У нас есть свой 3Д рендер, куча математики, процессинг высокополигональной геометрии и всё, таки, быстро работает. У мелко-мягких bing. Единственное где возникают проблемы это c gpu. Тут без плюсов пока сложно, а гибридайзером (или чем-то подобным) пользоваться не особо хочется.

              А вообще, это глупый спор… всегда использовались параллельно и никто не страдал…
                0
                К слову о GPU на С# и необходимость в С++. Есть такая здоровская библиотека для .NET Core, называется ILGPU. Она позволяет писать код, прям на С#, который потом выполняется на GPU (либо на CPU если карта не поддерживается), при этом без использования С++ и без необходимости знать синтаксис шейдеров.
                Конечно же, имеются ограничения и недочёты. Нельзя использовать ссылочные типы данных (ни классы, ни массивы), только структуры и встроенные в ILGPU типы. Последний раз когда я работал с этой библиотекой, там была поддержка только карт NVidia, ну и дебаг возможен был только при запуске кода на CPU либо танцы с бубнами в профилировщике от NVidia.
                Так что стоит сказать что и в этом направлении C# двигается (хоть и силами скромного комьюнити).

                P.S. очень уж порадовало то, что эта штука в итоге кроссплатформенная, и оооочень много времени сэкономило, так как данные были большие (гиперспектральные изображения на 5--700 МБ), и некоторые расчёты могли занимать 40 минут на CPU (против 3-4 секунд на GPU, и откуда взялся этот выигрыш в 600 раз я не осмелюсь объяснять).
              +3
              Когда говорят о кроссплатформенности, то нет смысла рассматривать сферический язык в вакууме, потому что в современном мире мало кому нужен язык сам по себе, без фреймворков, библиотек и среды разработки.
              Попробуйте-ка закодить, собрать и запустить бинарник с WPF-окошком, не выходя из Linux.
              А то так и Objective-C можно считать кроссплатформенным, только за пределами Apple-платформ он неюзабелен.
                +14

                Вы выбрали изначально не кроссплатформенный пример. Точно так же и на плюсах нельзя закодить какое-нибудь MFC-окошко, не выходя из Linux (что, имхо, не говорит в пользу MFC, но вряд ли годится в качестве аргумента против плюсов).


                А давайте теперь рассмотрим кроссплатформенный пример. На плюсах мы возьмём портабельную технологию Qt, а на C# — портабельную технологию Avalonia. И… ну, у нас выйдет закодить бинарник с окошком, не выходя из Linux. С некоторыми приседаниями мы его тут же заодно скомпилируем под Windows и macOS.


                Что дальше? Какие выводы можно сделать, и нужно ли их делать?

                  –2
                  xamarin
                  avalonia ui
                  сейчас почти любой язык предложит целую кучу технологий
                  которые предложат кроссплатформенность во всех возможных сферах
                    +12
                    Почему же тогда даже сама MS предпочитает писать кроссплатформенные приложения (Skype, Visual Code) на Electron? Наверное, с кроссплатформенностью .NET не всё так здорово?
                      +1
                      С кроссплатформенностью GUI там всё совсем плохо. То есть формально окошки и кнопки можно сделать одной библиотекой, но товарного вида под всеми тремя системами (Win, Linux, Mac) добиться очень тяжело.
                        +3
                        Насчет VSCode Eleсtron был обоснованным выбором, ибо прежде всего оно затачивалось под web разработку на js/ts. Eleсtron позволил быстро нарастить базу плагинов, так как стало просто интегрировать существующие инструменты из npm.
                        В том же sublime есть множество плагинов, которые являются лишь python оберткой над v8 для использования возможностей js библиотек.
                        Да и в целом VSCode работает достаточно шустро, пока не открывать в нем файлы с очень длинными строками.

                        Ну а Skype… Просто представим, что оно закрылось и больше не существует.
                          +1
                          Да и в целом VSCode работает достаточно шустро, пока не открывать в нем файлы с очень длинными строками.

                          По моёму поверхностному взгляду, даже быстрее чем Sublime
                          +4

                          Потому что сначала они разрабатывали вебовский редактор кода Monaco Editor для VS Online, а потом оказалось, что его можно упаковать в виде десктопного приложения...

                      +31

                      Весь спор похож на спор про автомобили с автоматической и механической коробками передач :) Нет ничего плохого в том, чтобы выбрать для комфортной городской езды в плотном потоке автомобиль с автоматической коробкой передач. Да больше расход топлива (читай ресурсов компьютера), да некоторая потеря контроля за поведением автомобиля (читай сборщик мусора), но в свою задачу решает и позволяет совершать более безопасные манёвры. Но если уж ты участвуешь в гонке, в которой трасса известна (читай знаешь какое железо), и фиксированное количество автомобилей (известные условия задачи), то уж придется сесть за механику, чтобы выжать из автомобиля максимум :)


                      При этом никто не мешает, ессно, и по городу ехать на механике и на гонке использовать затюненный автомат :)

                        +10
                        Я в целом согласен с вашим комментарием, но думаю вот что.

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

                        Поэтому на такие нюансы полезно проливать свет. А подобные споры как раз их и проливают: «вот сломается твоя автоматика — разоришься». Разумеется, из этого не следует «механика всегда лучше», но это ценная информация. И читать такие споры, по-моему, стоит не как «что лучше», а как полезную информацию о различиях.
                          0

                          Только в рамках этой аналогии давно придумали другие машины, которые едут не медленнее, но при этом безопасности и гарантий дают больше.


                          Да, тот же Rust, а до Rust — ATS какой-нибудь.

                            0
                            Только в рамках этой аналогии давно придумали другие машины, которые едут не медленнее, но при этом безопасности и гарантий дают больше.

                            Пример вам выше дан — вам осталось показать безопасность и «не медленнее». Хотя «не медленнее» вы уже показать не сможете, но хотя-бы безопасность покажите.

                              +1

                              Вы всерьёз будете утверждать, что C++ более безопасен, чем Rust?

                            0

                            Для быстрой реализации сложных концепций ИМХО Ruby/Python предпочтительней — это я к тому, что в большом проекте и 2 языков мало

                            +16
                            Анатолий: Мне кажется, что C# движется в сторону плюсов, он пытается отвоевать их рынок. А вот плюсы уже не движутся никуда.

                            Сергей: Откуда это? Что значит «плюсы не движутся никуда»?

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

                              +10

                              Я еще ни разу не видел конструктивных бесед ЯзыкХ вс ЯзыкУ :)

                                +1
                                Были такие беседы на моей памяти. Но в целом я не понимаю зачем ибо выбор языка должен исходить из условий стоящей задачи и доступных возможностей.
                                  0

                                  Да почему же. На мой взгляд это совсем не исключено и зависит скорее от того кто спорит.


                                  Правда я бы сказал что и сравнивать наверное надо не любые "сферические языки в вакууме", а языки более-менее "эквивалентные" в контексте какой-то конкретной задачи. Тогда вполне себе конструктивные дискуссии часто получаются.

                                  +2
                                  Полезно ещё и знание, а на каком языке X сделан сам язык Y
                                  Часть вопросов, тогда, сами отвалятся. :)
                                    0
                                    del
                                      0
                                      Это не значит вообще ничего. Да и в основном, языки написаны сами на себе. Условно компилятор Хаскеля написан на Хаскеле, и это спорно считается самой сложной программой, написанной на хаскеле:)
                                        +1

                                        Неудивительно. Это на самом деле вообще один из самых сложных компиляторов, если не самый сложный.

                                      +1

                                      Сергей на самом деле тоже имеет интересную позицию. То ему не нравится, когда есть компилтайм-надёжность («Я не хочу, чтобы моя программа что-то проверяла в compile time без моего ведома.»), то он считает, что модули существенно улучшат время компиляции (нет, не улучшат, время компиляции в современных плюсах идёт от шаблонов и constexpr-вычислений, а им модули не помогут никак).

                                      0
                                      Мне понравилось в графике расположение GO.
                                      Довольно приятно расположен.
                                        +1
                                        Дмитрий: Это очередная проблема. Есть у нас подход типа «модули». И я бы со своей колокольни сказал: ребята, мы переходим на модули и макросы больше не будут поддерживаться вообще никак. Более того, давайте со следующей версии, если включаешь модули, то отключаются макросы глобально везде. Вот это был бы мой подход. К сожалению, никто о таких кардинальных шагах не думает.

                                        Сергей: Почему, о них думают. Но их не поддерживает комитет. Наверное, есть причины. Но я тебе предлагают сделать proposal. Это же открытое всё.

                                        Дмитрий: Мы же понимаем, что это обречённый proposal. И обречён он по той причине, что никто не хочет внезапно сказать «надо переписывать»: допустим, в STL используются макросы, надо от них избавиться. Нужно, чтобы кто-то сделал волевое решение, сел и избавился от всех макросов.

                                        Бгыгы. Объясняю почему не трогают макросы и почему proparsal обречён: Как мне подключить модуль хидер в зависимости от платформы под которую это собирается? Как мне генерировать в коде имена переменных и функций? Где статическая рефлексия? Вот поэтому комитет и не трогает макросы потому что много кода просто невозможно переписать без них. Да есть всякие сторонние генераторы, но макросы поддерживаются любым компилятором из коробки, а с утилитами могут быть сложности, что делает концепцию ущербной как на уровне «поддержки из коробки» так и с вопросами кроссплатформы.

                                        P.S. «Магию» в Boost тоже стоит посмотреть ибо это фактически кусок STL feature или extented — как угодно можно назвать, но без Boost тяжко, а подключается он просто.
                                          0
                                          Как мне генерировать в коде имена переменных и функций? Где статическая рефлексия?

                                          Всё это есть тут:
                                          cppx.godbolt.org
                                          Можно собрать себе среду.
                                          Я попробовал, мне понравилось.
                                            0
                                            Бгыгы. Объясняю почему не трогают макросы и почему proparsal обречён: Как мне подключить модуль хидер в зависимости от платформы под которую это собирается?
                                            Точно так же, как это делается в тех языках, где модулей нет. И если вам где-то не хватает метаданных, напомню что это одна из проблем, которые модули могут теоретически решить. Conditional compilation на базе модулей — это плохо, помимо всего прочего это превращает код в нечитаемую кашу из #ifdef-ов. То что люди привыкли так работать не значит что это хорошо.
                                            Как мне генерировать в коде имена переменных и функций?
                                            Вы сейчас снова жалуетесь на тот функционал который, помимо того что он нишевый, не решается только путем макросов. В C#, например, можно автоматически присвоить переменной значение, равное названию вызываемого метода. Это делается на уровне кода, а не на уровне макросов. То что метаданные еще не подвезли это просто еще одна проблема, которую нужно решать вместо того чтобы натягивать сову на глобус.
                                            “Магию” в Boost тоже стоит посмотреть ибо это фактически кусок STL feature или extented — как угодно можно назвать, но без Boost тяжко, а подключается он просто.
                                            Любая “магия” (например, использование Boost PP) плохо читается и понимается, что приводит к вполне очевидным maintenance costs.
                                              0
                                              Вы сейчас снова жалуетесь на тот функционал который, помимо того что он нишевый, не решается только путем макросов.

                                              То что метаданные еще не подвезли это просто еще одна проблема, которую нужно решать вместо того чтобы натягивать сову на глобус.

                                              Ну да, всё так, а с учётом факта что в плюсы сейчас вливают успешно появившееся лет 10 назад, а кое что появилось и раньше, либо в других языках либо в куче внутренних pragma от компиляторов, то трогать макросы ещё долгов ближайшей перспективе никто не будет примерно с тем же определением это «мало кому и редко кому нужно, нишевая задача, уже работает везде одинаково, и т. д. и т. п.». Не знаю в чём уж совсем «ужас» макросов, с тем же успехом можно сказать что в регулярных выражениях тоже ведь «ужас». Макросы позволяют очень гибкую кодгенерацию из коробки, хоть и трудно поддерживаемую, но которую без полноценной рефлексии не сделать вообще никак.

                                              Кстати говоря constexpr выражения уже кое где позволили заменить макросы нормальным кодом, это уже очень хорошо и это правильное движение.
                                            +10

                                            Весь диалог типичный троллинг.
                                            В мусор егоб

                                              +3
                                              > в плюсах сейчас занимаются вещами, которые должны были появиться 10 лет назад.

                                              Я бы сказал 20 лет назад. Когда-то работал в ЦЕРНе, в команде ROOT (https://root.cern.ch/).
                                              Уже тогда у нас был C++ интерпретатор, Reflection, всевозможные контейнеры, тесный контакт с Страустрапом. Уже тогда обсуждалось, как добавить все эти фичи в стандарт C++.
                                              Но, воз и ныне там.
                                              Сейчас для «низкоуровневого» программирования (видео, DirectShow, MF, COM, железки) пользую C++. Для всего остального — C#.
                                              Мои любимые продукты DeExpress, Resharper.

                                                +4
                                                Уже тогда у нас был C++ интерпретатор

                                                То, что С++ нужно сейчас и просто «интерпретатор» — это разные вещи.

                                                Reflection

                                                Уровня «обойти поля пода»? Это тоже не то, что требуется от С++.

                                                Уже тогда обсуждалось, как добавить все эти фичи в стандарт C++.

                                                Да, но тогда это было позором. Эта была попытка напихать чего-то невнятного лишь бы напихать, но о чудо — комитет одумался.

                                                Для С++ не подходят решения других языков, но не это главное — подобных решений нигде не было и нет. Где есть компилтайм-рефлексия? Да нигде, а где есть — там на уровне языка существуют одни поды(либо чуть-чуть больше). Откуда всё это брать?

                                                За примерами далеко ходить ненужно. Достаточно посмотреть чем были концепты тогда, чем они являются сейчас. Я бы не хотел иметь то, что было раньше.

                                                И можно только порадоваться за С++, что комитет выбрать путь решения глобальных проблем, а не затыкания как попало локальных дыр. И лучше пусть не будет ничего, чем появится что-то убогое, что закроет путь чему-то адекватному.

                                                Тоже самое касается и рефлексии. Достаточно посмотреть на то, чем она была тогда(но уже тогда она была по-сути уникальной в своём роде. Даже в каком-нибудь D пошли по пути наименьшего сопротивления — сделали eval) и чем является сейчас. Лично мне и сейчас не нравится и противник ODR и всего, что с ним связано. В этом плане тот же шарп мне ближе.
                                                  +4
                                                  Я не хочу троллить.
                                                  Свою миллионную линию кода на C++ я уже написал.
                                                  Тем не менее, последние 10 лет работы на C#, убеждают меня, что C# на 101% более продвинутый язык развитие которого не стоит на месте (в отличии от C++).
                                                  На пример, мне нравятся те фичи, которые появятся в C#8 (хотя сам «застрял» на 4.5 ).

                                                  ++
                                                  >И можно только порадоваться за С++, что комитет выбрать путь решения >глобальных проблем, а не затыкания как попало локальных дыр.

                                                  Когда я говорил про «тесный контакт со Страустрапом» — это означает,
                                                  что были и продолжаются личные контакты, и Страустрап не раз приводил наш проект в качестве успешного проекта написанного на C++

                                                  Вот цитата из вики
                                                  "
                                                  ROOT разрабатывался как высокопроизводительная вычислительная библиотека, необходимая для обработки данных Большого Адронного Коллайдера, поток которых достигает нескольких петабайт в год. С 2009 года ROOT используется в подавляющем большинстве экспериментов физики высоких энергий; абсолютное большинство современных результатов и иллюстраций в этой области науки получено именно с использованием ROOT.

                                                  Включение в пакет интерпретатора C++ CINT значительно увеличило гибкость пакета, так как позволило использовать средства ROOT в интерактивном режиме или посредством написания скриптов, что сделало его похожим на MATLAB.
                                                  "
                                                  Более 10 лет назад комитет планировал ввести в стандарт C++, как интерпретатор, так и рефлексию.
                                                  Сам я когда-то написал apache module, который позволял исполнять C++ скрипты на серверной части. Что обеспечивало веб-интеграцию.
                                                  Именно по этому пути двигался C#.
                                                  +++
                                                  PowerShell — обеспечивает интеграцию C# с операционной системой.

                                                    +2

                                                    С++ тоже на месте не стоит. Но да, я наверное соглашусь что особенно в последнее время Microsoft стал очень активно развивать С#. Как впрочем и другие свои языки/фреймворки и всю сопутствующую "инфраструктуру"/тулинг.

                                                      +2
                                                      > Microsoft стал очень активно развивать С#

                                                      Когда-то я достаточно едко высказывался о Мише де Икаса, когда он начинал свой Mono, с GUI на основе Gtk++. Как я был не прав!

                                                      Но, именно Mono позволило портировать C# на Linux, iOS, Android.
                                                        –7
                                                        Но да, я наверное соглашусь что особенно в последнее время Microsoft стал очень активно развивать С#

                                                        microsoft и с++ начали активно развивать, но, чисто статистически, лучше бы они этого не делали
                                                        –3
                                                        Свою миллионную линию кода на C++ я уже написал.

                                                        Это не то, что нужно как-то выделять. В целом, возможно поэтому вам непонятно развитие С++(и как следствие современный С++).

                                                        Тем не менее, последние 10 лет работы на C#, убеждают меня, что C# на 101% более продвинутый язык развитие которого не стоит на месте (в отличии от C++).

                                                        Напихать сахара и рантайм-фичей ничего не стоит. С++ подобным не занимается. И далее какие-то странные тезисы без какой-либо аргументации.

                                                        На пример, мне нравятся те фичи, которые появятся в C#8 (хотя сам «застрял» на 4.5 ).

                                                        Типичное «хорошо там, где нас нет».

                                                        Когда я говорил про «тесный контакт со Страустрапом» — это означает,
                                                        что были и продолжаются личные контакты, и Страустрап не раз приводил наш проект в качестве успешного проекта написанного на C++

                                                        Из этого ничего не следует. Строуструп не священная корова и никогда кем-то, кто занимается С++ на фундаментальном уровне не являлся. Он всегда занимался популяризацией и доступностью С++, а не какими-либо теоретическими, либо практическими изысканиями.

                                                        И сейчас Строуструп работает именно на тем, что-бы искоренить подобное вашим представление. Которые где-то когда-то что-то писали на C++, которые лишь номинально являются С++, а реально си с классами.

                                                        C++ после 0x фундаментально изменился и всё, что вы знали до — уже ничего не значит. Весь ваш опыт до — уже ничего не значит. И core guidelines призваны изжить этот опыт, вынести его за рамки С++ и никогда не называть это C++, дабы не обманывать ни себя, ни других.

                                                        Включение в пакет интерпретатора C++ CINT значительно увеличило гибкость пакета, так как позволило использовать средства ROOT в интерактивном режиме или посредством написания скриптов, что сделало его похожим на MATLAB.

                                                        Это так же ничего не значит. Это попытка дать студентом очередной питон. Это не какое-то фундаментальное направление С++. К тому же, сама реализация подобного достаточно тривиальна на фоне того, что разрабатывается для С++ сейчас.

                                                        Более 10 лет назад комитет планировал ввести в стандарт C++, как интерпретатор, так и рефлексию.

                                                        Я уже на это отвечал. Рефлексии нигде нет и никто не знает как она должна выглядеть для вводных С++. С++ здесь занимает передовые позиции. Интерпретатор достаточно примитивная вещь, которая мало кому нужна.

                                                        С++ занимается развитием статических возможностей, возможностей мета-программирования и прочим подобным. Интерпретатор, скрипты и прочее — это совершенно иной подход, который не совместим с базовыми концепциями С++. Да, в какой-то мере что-то подобное имеет смысл поддержать, но это не приоритетно.

                                                        Задача статического языка прежде всего обеспечить фундаментальное свойство статики «собралось — работает». Это не питон и тут подобные проблемы не должны решаться реплом.

                                                        Что обеспечивало веб-интеграцию.
                                                        Именно по этому пути двигался C#.

                                                        Я не знаю каким образом скрипты дают какую-то веб-интеграцию и что это значит, но это так же не приоритетное направление С++.

                                                        PowerShell — обеспечивает интеграцию C# с операционной системой.

                                                        И что это должно значить? Лично меня не интересует ни эта «операционная система», ни какая-то интеграция в ней. Моё отношение к сему — есть ваше отношение к С++(вернее к тому, что вы неправильным образом называете С++).
                                                          +2
                                                          мой последний комментарий втему

                                                          > Интерпретатор достаточно примитивная вещь, которая мало кому нужна.

                                                          Это не примитивная вещь.
                                                          Когда четверть века назад Masaharu Goto (мой друг Маса) решил написать C++ интерпретратор (CINT), все в один голос уверяли, что это невозможно сделать.
                                                          А, он сделал. Конечно, за это время была проделана большая теоретическая работа по алгоритмам написания интерпретатора и сейчас это сделать гораздо проще.

                                                          Если бы 20 лет назад приняли C++ интерпретратор,
                                                          то все эти питоны, баши, пых-пыхи, пёрлы оказались в мусорной корзине истории.
                                                          Все заменил бы C++

                                                          Это именно тот путь (единый язык для любой задачи, везде C#) по которому пошли мелко-мягкие, и несомненно, это позволило им сделать прорыв в технологии программирования.
                                                          Не видеть этого может только человек страдающий когниктивным диссонансом.

                                                          > Рефлексии нигде нет и никто не знает как она должна выглядеть для вводных С++

                                                          Именно благодаря «рефлексии» был пойман Бизон Хиггинса, заполнена самая большая база данных в мире. Я имею ввиду данные с Большого Адронного Коллайдера. Это, так называемый, ROOT data format, который на 101% основан на «рефлексии».

                                                          ++
                                                          Хочу добавить последние 2 копейки…

                                                          Когда один из «экспертов» говорит

                                                          «Я тут хотел уточнить. Я про C# мало знаю, сам трогал его очень давно, в самых первых версиях»

                                                          дискуссию на этом можно было бы и закончить!

                                                        0
                                                        Решил таки продолжить…
                                                        Сегодня прослушал отличный доклад, про отличную либу, которая реализует рефлексию на C++ (14).
                                                        channel9.msdn.com/Events/CPP/CppCon-2016/CppCon-2016-C14-Reflections-Without-Macros-Markup-nor-External-Tooling

                                                        github.com/apolukhin/magic_get
                                                        Она уже часть boost.
                                                        Ждем, когда станет частью языка.
                                                      –7
                                                      У меня сломался Console.Beep() в C# + Windows + RDP.
                                                      Поплюсуйте, пожалуйста, на GitHub!
                                                      github.com/dotnet/corefx/issues/41437
                                                        –2
                                                        Кстати, в C++ он тоже должен быть сломан. Я не проверял.
                                                      +2

                                                      По поводу КДПВ: лучше бы взяли Саб-Зиро и Рейна из Ultimate Mortal Kombat 3, и тогда не пришлось бы перекрашивать Скорпиона.


                                                      Ultimate Mortal Kombat 3: Rain vs. Sub-Zero
                                                        +5
                                                        Да, мы сами это в рабочей переписке сегодня обсуждали, но к тому моменту пост уже был готов :)


                                                        +5

                                                        Для меня немного странная постановка вопроса и немного странная дискуссия. Сам в своё время начинал на С/С++, а потом всё больше и больше ушёл в С#. И для меня это просто немного разные "инструменты".
                                                        И сравнивать их это как сравнивать ну скажем топор и молоток. Вроде в чём-то похожие и местами один может худо-бедно заменить другой, но на мой взгляд не особо логично пытаться выяснить кто из них "лучше".

                                                          –4
                                                          Молотком можно только отбить палец. А топором обрубить себе процесс в продакшне.
                                                          +13
                                                          Анатолий: Мне, кстати, недавно попалась отличная статейка, где автор на разных языках (около 10) написал низкоуровневый драйвер — network driver для 10-гигабитной карточки Intel. От C до Swift, JS, Python и, естественно, C#. Если мы посмотрим на эти графики, которые у него получились, то C# на больших батчах (когда нивелируются расходы на запуск) идёт вровень с C и Rust.

                                                          Ну вот зачем упоминать этот позор. Как можно называть её отличной? Как можно говорить:

                                                          Если мы посмотрим на эти графики, которые у него получились, то C# на больших батчах (когда нивелируются расходы на запуск) идёт вровень с C и Rust.


                                                          Если кратко — это очередной ахренительный бенчмарк типа этой нетленки. Время идёт, а люди так и бенчат ffi на больших батчах. И ладно если первое имеет какой-то смысл(правда это нужно заявлять сразу, что мы бенчим именно ffi), то второе — это уже дно. Большие батчи нужны для уменьшения влияния ffi, но какой смысл бенчить ffi и при этом уменьшать его влияние? Какой смысл от быстрого ffi, если производится 1000 вызовов в секунду? Никто не знает.

                                                          Нужно сразу пресекать подобные заявления. А особенно неверные выводы из них. Несколько базовых тезисов:

                                                          1) Никто никакие драйвера не писал. Есть некое api, которые всё делает и железка его «поддерживает» — это api может получать данные из железки. Есть другое api, при помощи которого можно писать данные в определённое место, а далее само ядро всё разрулит. Т.е. вся логика драйвера существует в ядре, написана на си. Этот же «драйвер» просто конфигуратор + memcpy.

                                                          2) Почему-то во всех подобных бенчмарках за кадром остаётся самое важное? Что вообще в коде на разных языках происходит? Что там вообще выполняется? Как это выглядит.

                                                          За примером далеком ходить ненужно — достаточно взять упомянутый rust. Из тысячи строк на си — там получилось в 10(если не больше) раз больше кода. Почти весь этот код — unsafe-блоки с ffi к си. Где, собственно, rust и какой-то драйвер? Где та самая выразительность? Ради чего мы сменили шило на мыло?

                                                          3) Неверная идентификация проблемы. Правильные результаты там показывает именно начало графика. Проблемы C# обусловлены ни какой-то неведомой «когда нивелируются расходы на запуск» глупость, а вполне очевидными вещами.

                                                          Если упростить, то ситуация следующая. Ядро вызывает юзерпейс, далее всё это доходит до шарпа/раста/го(везде номинально есть «бесплатный» ffi), далее уже этот шарп/раст/го вызывает сишную логику, которая копирует данные и обеспечивает всё остальное.

                                                          Соответственно, всё сразу становится на свои места. Чем больший кусок данных мы пробрасываем через шарп/раст/го — тем меньше раз мы обращаемся к ним и тем меньше мы теряем на оверхеде. Т.е. по-сути чем правее — тем меньше шарпа/раста/го. А значит, что отсылка на правую часть графика — это призыв отказаться от шарпа/го/возможно и раста.

                                                            –2
                                                            Возможно, в некоторых моментах вы и правы, но мне кажется критика теста не вполне обоснована.

                                                            Драйвер в первую очередь это софт, реализующий какой-либо стандартизированный интерфейс, для того чтобы ОС могла как-то унифицированно общаться с огромным зоопарком железячных устройств. Обычный фасад, у которого понятное определенной ОСи лицо, и вызовы железного API определенной железяки (чаще всего через прерывания либо другую командную шину) или API драйвера более низкого уровня (например Video BIOS) под капотом. И совсем не обязательно это должен быть код, который байты по одному шлет в LPT порт. Уже много лет как придумана и активно используется в драйверописании такая замечательная штука как DMA. Собственно, очень многие драйверы, включая драйверы дисков, звуковых, сетевых и видео карт, занимаются в основном именно тем, что вы описали, — конфигурируют DMA буферы, напихивают в них данные и вызывают железячную команду «сделать хорошо». Поэтому пример который вы критикуете — драйвер в самом прямом понимании этого слова.

                                                            Линка над картинкой ведет на репу на гитхабе, где вполне можно почитать код и понять что делает та или иная реализация. И какие костыли использует — зачастую комментарии в коде или readme файлы явно указывают на них. В реализации на C# стек пакетов, все буферы (кроме DMA области) — менеджд код. Цикл обработки Tx/Rx, работа с PCI — тоже. Ясно, что полно unsafe (иначе невозможно работать с указателями в C#). Но в целом — вполне себе понятный C# код, без засилья маршаллинга, использования библиотек ядра и прочих грязных извращений.

                                                            Насчет размеров батчей и их влияния на производительность я бы тоже поспорил. С точки зрения драйвера, при большем размере батча нужно выделить больше буферов, создать больше дескрипторов и скопировать больше данных, но зато реже. И меньше PCI вызовов нужно делать чтобы передать то же самое количество пакетов. Так что повышение производительности с увеличением числа батчей свидетельствует лишь о дороговизне PCI вызовов, на что, собственно, и указывается в тексте статьи, поясняющей исследование. Причем судя по форме графика, вызовы PCI влияют на любую реализацию приблизительно одинаково, выходя к оптимуму на размере батча в 32-64 для всех языков. Так же ваша гипотеза плохо накладывается на тот факт, что дальнейшее увеличение числа батчей в итоге негативно сказывается на производительности (к сожалению, в оригинальной статье не указывается конкретное число, но я думаю, что эффект должен быть уже начиная с 1024, хотя может зависеть от железа).

                                                            Я согласен, что данный тест скорее показывает что на С#/Rust/Go/etc. можно писать драйвера с приемлемой производительностью. Так же, он позволяет грубо сравнить производительность тестируемых языков с C/C++ в определенном классе задач, типичном для С. Но в целом, все эти «20 мегапопугаев в секунду» в итоге ничего не говорят о языке и/или его применимости в задачах другого типа. Но в целом, да, тест приведен, возможно, не совсем к месту. Но от этого он сам не становится некорректным.
                                                              +3
                                                              Собственно, очень многие драйверы, включая драйверы дисков, звуковых, сетевых и видео карт, занимаются в основном именно тем, что вы описали, — конфигурируют DMA буферы, напихивают в них данные и вызывают железячную команду «сделать хорошо». Поэтому пример который вы критикуете — драйвер в самом прямом понимании этого слова.

                                                              Нет. И даже тут множество проблем. Конфигурирует ядро, через ядерное api, данные пропихивает ядро, обрабатывает ядро, вызывается ядро через сишный рантайм, взывает команду ядро. Т.е. в ядре работа с подобного рода устройствами уже почти реализована и обобщена.

                                                              Когда кто-то имеет ввиду драйверы — имеют ввиду именно драйверы. Драйверы в целом. Не «давайте из юзерспейса повызываем си через ffi». К тому же, даже это не всегда работает. Хотя казалось бы — что там может так сливать, но вот оно — может.

                                                              В реализации на C# стек пакетов, все буферы (кроме DMA области) — менеджд код.

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

                                                              Цикл обработки Tx/Rx, работа с PCI — тоже.

                                                              Там никакой логики нет, там всё примитивно — один шарповый синтаксический мусор и value-типы. Но даже тут оно умудряется сливать.

                                                              Какой смысл в шарпе? Что-бы написать «как на си», но при этом хуже чем на си? Если даже в таком явно подложном кейсе такие проблемы — что же там будет, если попробовать реализовать что-то действительно сложное.

                                                              Ясно, что полно unsafe (иначе невозможно работать с указателями в C#). Но в целом — вполне себе понятный C# код, без засилья маршаллинга, использования библиотек ядра и прочих грязных извращений.

                                                              А что же такое /sys, хотя это не библиотека да, но api ядра. К тому же, как я уже говорил выше — это не понятный C# код. Это банальный си раздутый синтаксисом шарпа и содержащий всякие заморочки.

                                                              Я не понимаю вашу логику. Какой смысл брать шарп и писать «как на си»? Это имеет какой-то сакральный смысл? Я этого никогда не понимал. Для людей из мира си — подобные вещи привычны, подобная работа с памятью привычна, подобные api привычны. Что мы получаем используя шарп? Мы получаем выразительность? Нет. Мы уходим от каких-то проблем? Нет — мы их создаём. Мы используем шарп в привычном виде? Нет. Мы получаем тот же результат? Нет. Что мы получаем?

                                                              Насчет размеров батчей и их влияния на производительность я бы тоже поспорил. С точки зрения драйвера, при большем размере батча нужно выделить больше буферов, создать больше дескрипторов и скопировать больше данных, но зато реже. И меньше PCI вызовов нужно делать чтобы передать то же самое количество пакетов. Так что повышение производительности с увеличением числа батчей свидетельствует лишь о дороговизне PCI вызовов, на что, собственно, и указывается в тексте статьи, поясняющей исследование. Причем судя по форме графика, вызовы PCI влияют на любую реализацию приблизительно одинаково, выходя к оптимуму на размере батча в 32-64 для всех языков. Так же ваша гипотеза плохо накладывается на тот факт, что дальнейшее увеличение числа батчей в итоге негативно сказывается на производительности (к сожалению, в оригинальной статье не указывается конкретное число, но я думаю, что эффект должен быть уже начиная с 1024, хотя может зависеть от железа).

                                                              Я не понимаю к чему вы и зачем это пишите? Вы нигде не опровергли мою гипотезу — только подтвердили её.

                                                              Очевидно, что на любых вызовах есть оверхед. Каким образом наличие оверхеда снизу что-то говорит об оверхеде сверху? Зачем вы пытаетесь манипулировать? К тому же, вы зачем-то пытаетесь меня обмануть.

                                                              Си выходит на максимум ещё на 8-16, когда как шарп не выходит никогда. Куда-то он выходит — только 128-256, но даже тут оверхед есть. То, что «другие языки» так же растут — это так же очевидно. Оверхед на ffi и на саму логику языков размазываются по батчу.

                                                              По поводу «эффект должен быть» — это глупость. Как мы уже выяснили — существует две компоненты. Компонента снизу и сверху, ведь си точно так же растёт и оверхед там тоже есть, как и есть он железе. таким образом ничего не мешает это компоненте снизу начать проявлять себя и снижать производительность. Когда как компонента сверху может уже либо совсем не влиять, либо влиять меньше. К тому же — наличие эффекта не означает, что он одинаково влияет на все языки.

                                                              К тому же, размер батча увеличивает летенси и где-то это может критично.

                                                              Я согласен, что данный тест скорее показывает что на С#/Rust/Go/etc. можно писать драйвера с приемлемой производительностью.

                                                              Из этого горе-теста ничего этого не следует. К тому же — удобно вы трактуете для себя приемлемость. Питонисты тоже скажу, что для них их производительность приемлемая.

                                                              К тому же, раст в данном случае лучше вообще не упоминать. Там всё очень плохо в этой реализации. Если версию на шарпе ещё можно с натяжкой назвать «версией на шарпе», то вас про раст так не сказать. Го я не смотрел, но меня не особо го/шарп интересуют.

                                                              Так же, он позволяет грубо сравнить производительность тестируемых языков с C/C++ в определенном классе задач, типичном для С.

                                                              Не позволяет. Это фейковый бенчмарк, который ничего не бенчит. К тому же, вы только что поймали себя в ловушку. Если до этого тезиса вы могли бы говорить, что мои рассуждения об:

                                                              Когда кто-то имеет ввиду драйверы — имеют ввиду именно драйверы. Драйверы в целом. Не «давайте из юзерспейса повызываем си через ffi». К тому же, даже это не всегда работает. Хотя казалось бы — что там может так сливать, но вот оно — может.


                                                              Надуманы, но вы действительно сделали то, что я и говорил. Вы начали экстраполировать результаты этого позора на класс задач. Я не буду комментировать состоятельность этих заявлений — она попросту нулевая. Если даже в таком подложном бенчмарке, который ничего не бенчит и слить там попросту невозможно — вся тройка сливает — это полное фиаско.

                                                              Но в целом, все эти «20 мегапопугаев в секунду» в итоге ничего не говорят о языке и/или его применимости в задачах другого типа. Но в целом, да, тест приведен, возможно, не совсем к месту. Но от этого он сам не становится некорректным.

                                                              Становится. Он некорректен целиком и полностью. Как я уже писал — он ничего не бенчит. Вообще, примерный аналог подобного я показал выше. У него так же много защитников, которые пытаются экстраполировать эти результаты на вычисления.

                                                              Во всех подобных бенчмарках надо чётко понимать — что мы бенчим и что выполняет основную работу. В конечном итоге, как я и сказал — этот бенчмарк бенчит ffi и сишный рантайм. Он не бенчит ничего иного. Хотя даже как бенчмарк ffi он плох. Он плох во всём.

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

                                                                0
                                                                Я согласен, что данный тест скорее показывает что на С#/Rust/Go/etc. можно писать драйвера с приемлемой производительностью.


                                                                Насколько понимаю, драйвер должен работать в режиме kernel mode, а эти языки обеспечивают только user mode. То есть есть накладные расходы на переключение между режимами при каждом чихе. Чистый kernel mode возможен только на С и ассемблере. Даже С++ не может работать в этом режиме понормальному.
                                                                  +3

                                                                  Rust и плюсы могут работать в чистом kernel mode, нужно лишь отключить фичи рантаймов.
                                                                  Ну и учитывая специфику, не увлекаться шаблонами.

                                                                    0
                                                                    В каком-то ограниченном диапазоне могут. Еще вопрос — на какой платформе — Window или unix?
                                                                      +1

                                                                      Вот прямо сейчас на redox-os. В остальных случаях особо тоже не вижу проблем фундаментальных.
                                                                      А вообще, интересная идея в том, чтобы вообще не использовать кольца защиты и полагаться на изоляцию wasm рантайма.
                                                                      В интернете где то лежит прототип такой оси.

                                                                      0
                                                                      Ну и учитывая специфику, не увлекаться шаблонами.

                                                                      Это в смысле для снижения размера бинарника?

                                                                        –1
                                                                        Не использовать кучу, например ;) А это значит, что, к примеру, std::string в драйвере уже нельзя использовать, но зато std::string_view можно.
                                                                +2

                                                                По мне все эти споры больше дело вкуса. Мне допустим Java кажется намного логичнее C# из-за меньшего количества сущностей, и ничего не могу поделать.
                                                                Последние изменения стандарта C++, как мне кажется — попытки исправить проблемы которые привнесло метапрограммирование.
                                                                А ещё я на днях посмотрел пост про развитие стандарта C, прямо все больше и больше люблю С, очень стройный и логичный язык.
                                                                Вот ссылка, кому интересно.

                                                                  0
                                                                    –2
                                                                    Последние изменения стандарта C++, как мне кажется — попытки исправить проблемы которые привнесло метапрограммирование.

                                                                    Странное заявление. Как можно исправить проблемы метапрограммирования добавив его ещё больше? Клин клином? Проблемой С++ было(и есть) малое кол-во метапрограммирования и малое ко-во фич. А так же, проблемой С++ является его изначальный дизайн со множеством скрытой семантики и откровенных дыр, но такой дизайн присущ всем ЯП.

                                                                    А ещё я на днях посмотрел пост про развитие стандарта C, прямо все больше и больше люблю С, очень стройный и логичный язык.

                                                                    Видео запоздало лет на 20. Всё это(и больше) всегда было в gnuc(который стандарт де-факто в мире си), откуда и перебралось в стандарт, причём почти всё перебралось ещё те самое 10-20 лет назад.

                                                                      +2
                                                                      Как можно исправить проблемы метапрограммирования, добавив его ещё больше?

                                                                      Сделав код проще и понятнее, пусть и за счёт усложнения самого языка.

                                                                        0
                                                                        Сделав код проще и понятнее, пусть и за счёт усложнения самого языка.

                                                                        Ну дак там говорится не о сложности мета-программирования(хотя тезис уже спорный — где есть ещё более простое мета-программирование? В D? Мне лично не особо оно нравится и выглядит, опять же для меня, ужасно), а о самом мета-программировании.

                                                                        К тому же именно мета-программирование сделало из C++ то, чем он является и решило множество проблем везде и всюду. Тезис абсолютно некорректен. А то, что его можно упростить и улучшить — да, конечно. Но тезис всё равно некорректный.

                                                                          0
                                                                          хотя тезис уже спорный — где есть ещё более простое мета-программирование?

                                                                          Ну да, ассемблер простой. Но программы писать на нём почему-то сложно. Поэтому люди придумали высокоуровневые языки.


                                                                          Кстати, именно в C++ мета-программирование называть простым у меня язык не поворачивается. Концептуально всё просто, но из-за большого количества подводных камней получается уже сложно.

                                                                      +2
                                                                      Мне допустим Java кажется намного логичнее C# из-за меньшего количества сущностей, и ничего не могу поделать.


                                                                      В java до сих пор нет checked arithmetics.
                                                                      int foo = Integer.MAX_VALUE + 1; // тут должно быть исключение, а его нет. источник трудноуловимых отсроченных ошибок
                                                                        +3
                                                                        Мне допустим Java кажется намного логичнее C# из-за меньшего количества сущностей, и ничего не могу поделать.

                                                                        А мне Java не нравится из-за ограниченных языковых возможностей по сравнению с C#. Даже структур нет и полноценных дженериков.


                                                                        Аналогично кому-то будет нравиться Go за простоту, а кому-то C++ — за возможности.

                                                                        0
                                                                        А по мне самый лучший ЯП, это тот который ты лучше освоил.
                                                                          +2

                                                                          Я освоил Basic разлива УК-НЦ по максимуму, и я гарантирую, что это не лучший язык даже среди тру-бейсиков.

                                                                            0
                                                                            Та ладно таких веселых васиков больше нигде нет. Если в видеопамять по отрицательному адресу писать оно рисует отам вверху экрана, где типа верхней строки состояния. И убрать то что нарисовал никакими комадами clear и т.д. не уберешь. только ребут ну или опять же программно затереть. Информатичку чуть инфаркт не хватил когда она там логотип IBM увидела и убрать не шмогла.
                                                                            0
                                                                            Ага, Форт, тут и метапрограммирование и разделение синтаксиса и семантики и низко-высокоровневые слои применения языка, но увы слишком много отличий от майнстрима и корпоративного использования. :)
                                                                            –1

                                                                            Хотел бы я посмотреть как придёт самсунг и скажет мелкософту что этой фичи в новом дотнете не будет. Практически весь c# контролируется мелкософтом, любой форк, предлагающий координальные изменения будет раздавлен в течение пары дотнетовских версий. Опять же под линь и мак никто не пишет на c#, несмотря на xamarin. Все понимают что это язык одной компании под одну операционку, но продолжают утверждать, что он кроссплатформенный и его развитие распределено.

                                                                              +1

                                                                              Под одну операционку это ныне замороженный (is done) .NET 4.8.


                                                                              А актуальный .NET ныне — это Core 2.2/3.0 для бек-енд разработки, которую ведут обычно под Windows, но таргетируют как для Windows, так и для Linux.


                                                                              И сейчас Core прямо выстрелил — после многих и многих лет застоя стартовало много бек-енд проектов на рынке.


                                                                              Ну а с кроссплатформенной разработкой, похоже, в итоге не сложилось. И надо ли? Есть много других современных средств.

                                                                                0
                                                                                Можно писать на vscode под линуксами, но debuger придется от самсунга прикручивать, либо пользоваться проприетарным от микрософт в комплекте с vscode.
                                                                                  +1

                                                                                  Rider под linux работает не намного хуже, чем под wndows. А в чем-то даже лучше.

                                                                                    +2
                                                                                    Юзаю Core 2.3. Так вот, один из самых важных фреймворков — Entity Framework до сих пор до ума не допилен. Год назад, когда я на него перешёл, там не было GROUP BY (!), за год вот появилось, также как и конструкция IN. Но до сих пор нет UNION, какие-то проблемы были с DISTINCT (сейчас не вспомню что именно, но были). Про enity-sql и говорить не приходиться. Хотя непосредственно ASP .NET Core мне зашёл больше чем виндовс-онли ASP .NET MVC, благодаря многим улучшениям.
                                                                                      0
                                                                                      Уже лучше. EF Core 3.0 имеет еще более допиленный Change Tracker, Code First, и чуток лучший парсер Expression Tree, но это не значит лучший SQL. Использовать ли это в продакшине, хотя нет, использовать ли это для высоких нагрузок — решать вам.
                                                                                        0
                                                                                        В 3.0. так и не завезли пока union. Я-то кое-как выкртился, а вот в теме на гитхабе по union много тех, кто печалится от этого.
                                                                                          0
                                                                                          Как это не завезли??? Видать «конкуренты» до сих пор абстрактной «фигней» над абстрактным хранилищем страдают.
                                                                                          Для жаждущих пока только для 2.1, на след неделе докручу к 3.0, а то немножко там нарефакторили и надо легкий тюнинг — linq2db.EntityFrameworkCore
                                                                                          Редко меня можно удивить SQL запросом который я не могу на LINQ написать.
                                                                                        +1
                                                                                        Мое мнение, что когда в запросах доходит дело до GROUP BY и прочие UNION, то в большинстве случаев я хочу дернуть хранимку чтобы быть уверенным, что оно работает как я хотел.

                                                                                        Лично я 2 года в продакшене использую EF Core и не было того, чтобы я сделать не смог. Не всегда элегантно, но работало. Плюс перформанс, если использовать AsNoTracking весьма хорош, по сравнению с обычным или упаси Боже, нхибернейтом.
                                                                                          0
                                                                                          Ну я всегда после написания чего-либо на LINQ проверяю через профилировщик (или как он там). Вспомнил, кстати, в чём проблема с DISTINCT. Конструкция типа: COUNT (DISTINC ...)… GROUP BY пока не преобразуется в SQL.
                                                                                            0
                                                                                            Может еще и оконные функции вспомним? И, думаю, никогда или не очень скоро будет поддерживаться. Разрабатывают EF Core очень квалифицированные специалисты, но к реальной разработке высоконагруженных систем, имеющие далекое отношение. По этому не удивляйтесь поставленным приоритетам.
                                                                                              0
                                                                                              Причем тут высокая нагрузка (особенно с Union, ага). Ни разу не видел, чтобы ОРМ использовали для высокой нагрузки. Для этого просто дергаем хранимку/вьюху из базы, где ее пишет DBD, а не EF с горы. Да, это гораздо медленнее в разработке, но когда я думаю про хайлоад, я подразумеваю, что деньги на ДБД и время на нормальную разработку есть.
                                                                                                0
                                                                                                Меня в целом устраивает Ef core, так или иначе получалось обойти все ограничения и добиться нужного без использования хранимок. Asnotraking, кстати, в моем случае прибавил не производительности, а снизил потребление оперативки (ну и оптимизация некоторых linq конструкций тоже резко снизила потребление оперативки).
                                                                                                Просто переход с классического EF на EF Core полтора года назад был достаточно неприятным (в классике активно использовался Entity SQL) и самым сложным моментом из всего перехода с ASP.NET MVC на ASP.NET MVC Core. А использовать классический EF на Core было как-то не красиво.
                                                                                                  0
                                                                                                  AsNotraking снижает потребление памяти в классических REST сценариях, когда по-сути, контекст живет только время обработки реквеста. Мы просто не кэшируем в памяти всю эту хрень.

                                                                                                  А в чем были именно сложности перехода? Есть конечно костыли до сих пор, но особых сложностей я не видел.
                                                                                                    0
                                                                                                    Основная проблема была в том, что 3/4 запросов при переходе превратились в тыкву. Ну т.е. почти все запросы сложнее SELECT… JOIN… WHERE и UPDATE… WHERE. В итоге большинство хоть сколько-то сложных запросов вылились в SELECT * FROM tableName1 с последующей работой уже в памяти. В процессе переписывания обнаружилось, что на тот момент не поддерживался GROUP BY, что было вообще больно. К счастью, апдейт с GROUP BY пришёл довольно скоро, что упростило многие вещи. На старом EF запросы были написаны достаточно небрежно, благо он прожёвывал почти любые конструкции LINQ преобразуя их в SQL. Ну и при переходе на EF Core — пришлось всё заново осмысливать. Однако, это привело к ускорению этих запросов и меньшему потреблению памяти. Правда, через пол года были дополнительные действия по оптимизации расходов оперативки, включая тот самый AsNoTracking, приведение любых коллекций LINQ к ToList (это особенно много местами жрало памяти из-за многократных бессмысленных вычислений), добавлено кеширование всяких менюшек и прочих элементов, требующих частых одинаковых запросов. Но до сих пор ещё приложение при старте иногда, внезапно, съедает на 150мб памяти больше чем обычно (~400 мб вместо ~250 мб). Причину пока не установил, но где-то я явно напортачил.
                                                                                                      0
                                                                                                      1. Пропал Model First подход. Это, конечно же, был наиболее неудобный из всех подходов, но переписать легаси всё равно не так просто.


                                                                                                      2. Пропали инструменты для автоматизации Database First — подхода.


                                                                                                      3. То, что раньше делалось через edmx, теперь надо делать через DbModelBuilder. Стало намного проще, но все старые костыли снова в мусорку.


                                                                                                      4. Entity SQL тоже пропал, запросы надо переписывать


                                                                                                      5. Довольно неудобно, что сам EF Core вроде как для .NET Standard написан, но вот для миграций нужен .NET Core и никак иначе.


                                                                                                    0
                                                                                                    Потому EF не может. Хранимки это и есть костыли. Шаг влево, шаг вправо — FromSql или хранимки. Выигрыш использования LINQ слегка пропал. Если в инструменте сплошные ограничения, я чувствую себя как на минном поле. Но ниче, потом так и рождаются сертифицированные специалисты — они знали, они плавали.
                                                                                          0

                                                                                          Это Вы из какого года нам пишете?
                                                                                          Сообщество очень активно участвует в разработке с 2014 года, причем изменения далеко не минорные. Например, привнесение платформенных SIMD в 3.0 сделано не разработчиком MS, насколько я знаю. И форки при таком подходе не нужны абсолютно, более того — они вредны.

                                                                                          0
                                                                                          У .NET есть куча ужасных косяков со скоростью в некоторых системных вещах.
                                                                                          Например получения и обработка всех файлов в директории.
                                                                                          На WinAPI эта часть может работать до 10 раз быстрее, чем на truъ .NET-е.
                                                                                          В итоге C++ CLI для таких задач лучше всего (боль маршалинья всех WinAPI на C# невыносима)
                                                                                            –10
                                                                                            При этом если учесть что шарп это вооще не C а ява++ то все становится на свои места. Это не какой не С++++ а Simula-67++++.
                                                                                            Ну а если к этому присовокупить что GC полностью устарел по состоянию на конец 60-х потому что для ООП не дает вообще никакой автоматизации и в купе с неумением статической композиции и размещения временных объектов на стеке, полностью исключают многопоточность, превращая ее в эмуляцию однопотока на многоядерном проце, дженерики не позволяют определять алгебру над сущностями, модули паскалевского разлива не позволяют иметь несколько реализаций к одному заголовку и несколько заголовков к одной библиотеке…

                                                                                            Ну в общем сразу становится ясно почему С++ наиболее высокоуровневый язык на сегодняшний день. А то что быстрый и годен для системного уровня — ну так получилось.
                                                                                              +6

                                                                                              Вроде как шутки про GC уже давно deprecated

                                                                                                –3
                                                                                                Ну да. Очень давно. На конец 60-х стало отчетливо ясно что он полностью непригоден для ООП. А в начале 80-х во всех профессиональных ООП языках от него отказались в пользу более совершенной, гибкой и эффективной кастомизируемой автоматики управления жизненным циклом.
                                                                                                +2
                                                                                                размещения временных объектов на стеке, полностью исключают многопоточность

                                                                                                Вообщето C# умеет размещать объекты на стеке правда только struct. И как это мешает многопоточности?
                                                                                                  –2
                                                                                                  В стандартной библиотеке классы которой и используются в основном как временные каков процент оных struct?
                                                                                                  А любой new при создании их на эмулированном общем стеке (это то что ошибочно называют кучей в шарпе) требует синхронизации доступа к указателю оного стека. Т.е. все потоки выстраиваются в очередь на каждом шагу.
                                                                                                  При размещении же объектов на аппаратном стеке, который для каждого потока свой, такая синхронизация не требует. При этом в реалиях плюсов свою субкучу для каждого потока иметь — ну это вопрос зависящий только от необходимости такой субкучи для конкретной задачи, и вся автоматика управления жизненным циклом для такой субкучи продолжает работать в штатном режиме.
                                                                                                  В отличии от шарпа где и с организацией субкучи поплясать с бубном придется и GC в ней работать точно не будет.
                                                                                                    +3

                                                                                                    Мне кажется, вы застряли где-то на уровне .NET 1.0.

                                                                                                      +1
                                                                                                      Ну да ведь в параллельных потоках обязательно нужно выделять новые объекты, нельзя же работать с существующими или использовать локфри пулы, или сотню других алгоритмов.
                                                                                                      А любой new при создании их на эмулированном общем стеке (это то что ошибочно называют кучей в шарпе) требует синхронизации доступа к указателю оного стека.

                                                                                                      хм… Интересно где вы подобное прочитали? Вообще вопрос выделения памяти в С# довольно таки сложный (хотя по вашему он простой и тупой как 5 копеек), они используют столько уловок, что выделение памяти в C# работает быстрее нежели родной и горячо любимый malloc, и я почему то более чем уверен, что аллокация в C# локфри, особенно если учитывать как легко пишутся лофри аллокаторы (из собственного опыта написания локфри аллокаторов)

                                                                                                      И да, чуть не забыл, структурные переменные в C# которые на стеке создаются без new
                                                                                                        –2
                                                                                                        что выделение памяти в C# работает быстрее нежели родной и горячо любимый malloc

                                                                                                        Единичный new в шарпе иногда быстрее. Но только исключительно за счет гигантского отложенного оверхеда. При этом если учесть тот факт что вызовать new в плюсах надо в сотни раз реже чем в шарпе то как бы шарп в этом плане отстает в десятки раз. Это при том что глобальный new в плюсах не предназначен для создания мелких единичных объектов хотя и может для этого использоваться. В основном он используется для создания субкуч выделение из которых идет по оптимальному для обслуживаемой структуры данных алгоритму.
                                                                                                          –2
                                                                                                          работает быстрее нежели родной и горячо любимый malloc

                                                                                                          в синтетическом тесте который использует менее 50мб предвыделенной памяти для там нескольких тысяч распределений когда плюсы отгрызают эту память у оси постранично и с игнорированием того факта что в плюсах вместо эти нескольких тысяч вызовов new достаточно одного который выполняется в тысячи раз быстрее даже с отгрызанием памяти?
                                                                                                            0
                                                                                                            Ды нет, если не писать свой аллокатор для плюсов, то шарповый аллокатор всегда быстрее, за исключением может только больших кусков памяти.
                                                                                                            –1
                                                                                                            Ну да ведь в параллельных потоках обязательно нужно выделять новые объекты, нельзя же работать с существующими или использовать локфри пулы, или сотню других алгоритмов.
                                                                                                            ну к примеру вектора складывать, матрицы перемножать и т.д. и т.п. И промежуточные результаты таких операций как не крути а временные объекты.
                                                                                                              0
                                                                                                              Да но они не создаются через new, а ещё можно так M1 *= M2.
                                                                                                              –2
                                                                                                              Вообще вопрос выделения памяти в С# довольно таки сложный (хотя по вашему он простой и тупой как 5 копеек)

                                                                                                              Да нет там никаких уловок. Просто смещается указатель на конец эмулированного стека. Поэтому сам new и быстрый всегда O(1), а у плюсов глобальный new O(1) только на полностью нефрагментированной куче, на фрагментрированной O (Log (n)) от количества свободных дыр. Но зато имеет постоянный гигантский оверхед по содержанию живых объектов, пропорциональный O(n) от живых объектов, в отличии от плюсов которые тратятся только на рождение и похороны, причем преимущественно массовые. Это уже не говоря про отложенный оверхед на абсолютно бесполезную в системе со страничной организацией виртуальной памяти дефрагментацию, без которой GC жить не может, и этого «быстрого» new тоже не будет.
                                                                                                                +1
                                                                                                                Ох лол, и вы говорите это просто. Дефрагментация памяти, бесполезная, да вот только благодаря ей C# сильно обгоняет С++ в выделении памяти, а ещё делает вычисления более кэшфрендли.
                                                                                                                  –3
                                                                                                                  Дефрагментация памяти, бесполезная, да вот только благодаря ей C# сильно обгоняет С++ в выделении памяти
                                                                                                                  Зато очень сильно отстает в хранении.
                                                                                                                  а ещё делает вычисления более кэшфрендли.

                                                                                                                  Этой байке уже реально 70 лет. Только не кеш френдли а минимизирует перемотку перфоленты. У вас ОЗУ до сих пор на перфоленте? Алииния кеша она как не крути 64 байта. А за ними промах.
                                                                                                                    –1
                                                                                                                    Вы не понимаете о чём говорите, попишите высокопроизводительные программы и поймёте насколько велико значение кеша.
                                                                                                                      +1

                                                                                                                      Так в высокопроизводительных программах просто берут arena allocator и получают предсказуемую дружественность к кешу, а не рассчитывают на умный рантайм.

                                                                                                                        0
                                                                                                                        Само собой, я просто говорю, что его утверждения про то что кеш не имеет особого значение не соответствуют реальности.
                                                                                                                          –1
                                                                                                                          что его утверждения про то что кеш не имеет особого значение не соответствуют реальности
                                                                                                                          Где то сказано что он не имеет значения? Сказано что дефрагментация тут не при чем вообще.
                                                                                                                –1
                                                                                                                что аллокация в C# локфри, особенно если учитывать как легко пишутся лофри аллокаторы (из собственного опыта написания локфри аллокаторов)

                                                                                                                Локфри она может быть только из разных субкуч/пулов а соответсвенно должен быть механизм явного назначения субкучи/пула потоку.
                                                                                                                И как понимаю GC с объектами выделенными из этих пулов тоже не дружит?
                                                                                                                  +2

                                                                                                                  Gen0 у каждого потока свой, если что

                                                                                                                    0
                                                                                                                    у системных потоков в которых каллбеки от ядра приходят тоже?
                                                                                                                      +1

                                                                                                                      У вас нет доступа к системным потокам из пользовательского кода.
                                                                                                                      Колбэки от ядра могут приходить только в пользовательские потоки.

                                                                                                                        –1
                                                                                                                        Колбэки от ядра могут приходить только в пользовательские потоки.
                                                                                                                        Т.е. только через синхронизацию потоков. Толку тогда от этого эмулированного мультистека, если работа без синхронизации потоков не обеспечивается в принципе?
                                                                                                                          +1

                                                                                                                          Это, если что, ограничение самой операционной системы, а не языка/фреймворка.

                                                                                                                            –2
                                                                                                                            Это, если что, ограничение самой операционной системы, а не языка/фреймворка.
                                                                                                                            Та нет таки фреймверка. Все калбеки api приходят ни разу не в вызывающем потоке. И вообще не разу не в потоке создаваемом пользовательским кодом. При этом по одному и тому же хендлу разные вызова одного и того же каллбека могут приходить в разных потоках.
                                                                                                                              +1
                                                                                                                              И вообще не разу не в потоке создаваемом пользовательским кодом.

                                                                                                                              Неверно. Колбэки приходят в потоки, создаваемые пользовательским кодом.

                                                                                                                                –1
                                                                                                                                Неверно. Колбэки приходят в потоки, создаваемые пользовательским кодом.

                                                                                                                                А вы их средствами чистого winapi когда нибудь вообще получали что так утверждаете? В главный поток окна они попадают совсем другим спсобом — подкапотный обработчик фреймверка в вызываемый в потоке api, записывает параметры вызова и отправляет их мессаджем. А уже поток обрабатывающий сообщения вызывает делегата.
                                                                                                                                  0

                                                                                                                                  Конечно, получал. И если вы почитаете документацию по функциям WinAPI, вызывающим колбэки, то там всё будет написано, что и где вызывается.


                                                                                                                                  Вот, например:
                                                                                                                                  https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfileex


                                                                                                                                  Колбэк вызовется в текущем потоке, если он будет в alertable state — т.е. в состоянии Sleep/Wait.

                                                                                                                                    –2
                                                                                                                                    Колбэк вызовется в текущем потоке, если он будет в alertable state — т.е. в состоянии Sleep/Wait.

                                                                                                                                    Вообще то каллбеки ставят не для того чтобы их в слипе ждать. Особенно когда вопрос касается дуплексного сетевого ввода-вывода. При этом к примеру от той же WinHTTP каллбеки всегда в другом потоке приходят.
                                                                                                                                      0
                                                                                                                                      Вообще то каллбеки ставят не для того чтобы их в слипе ждать. Особенно когда вопрос касается дуплексного сетевого ввода-вывода.

                                                                                                                                      А переключение контекста бесплатное, ага. То-то однопоточная асинхронщина показывает высокую эффективность под большой нагрузкой.


                                                                                                                                      При этом к примеру от той же WinHTTP каллбеки всегда в другом потоке приходят.

                                                                                                                                      В случае WinHTTP колбэки вызываются в пуле потоков, создаваемым самой либой в пользовательском режиме. Просто эта либа некоторые вещи делает за вас, внутри неё примитивы те же самые.


                                                                                                                                      А .NET перехватывает создание потоков через DLL_THREAD_ATTACH и корректно их инициализирует, чтобы пользователь мог не думать о CLR и GC вообще.

                                                                                                                    0
                                                                                                                    зачем явно то назначать? И без явного всё работать будет, в любой функции в любом месте можно получить id потока в котором она работает.
                                                                                                                    –3
                                                                                                                    пишутся лофри аллокаторы (из собственного опыта написания локфри аллокаторов)

                                                                                                                    т.е. и 20 лет помучались и поняли таки что памятью надо управлять вручную, хотя это было доказано еще 50 лет назад?
                                                                                                                    Ну в общем если шарп до ума довести то однозначно плюсы получатся.
                                                                                                                    Интересно сколько времени у шарперов займет понять что кроме ручного управления памятью еще и автоматика управления жизненным циклом нужна, которая в плюсах уже лет сорок есть?
                                                                                                                      +1
                                                                                                                      Не, это из С++ опыта, я просто плюсовик, С++ мой любимый язык, обожаю метапрограммирования и ненормальное программирование, C# на самом деле в работе не использую, но честно признаю (ибо сам тестил) что в C# выделение памяти работает намного быстрее стандартного малока.
                                                                                                                      автоматика управления жизненным циклом нужна, которая в плюсах уже лет сорок есть?

                                                                                                                      Вы про IDisposable чтоли который в C# очень очень давно появился?
                                                                                                                        0
                                                                                                                        Я про автоматическое управление жизненным циклом. Про автоматическую деинициализацию объекта при выходе его из скопа/деинициализации содержащего его объекта. Именно это позволяет кастомизируемо решать задачу автоматического управления как ресурсами/объектами так и взаимосвязями объектов. Память при этом рассматривается как вид ресурса.
                                                                                                                        GC этого не умеет от слова совсем. Да и задачу управления буферами памяти GC решает только в случае если задача управления взаимосвязями полностью решена. иначе течет косвенными утечками. Ручное же решение задачи управления взаимосвязями ничем не отличается от ручных вызовов delete и при этом делает GC абсолютно ненужным.
                                                                                                                          +1
                                                                                                                          Структуры удаляются, у IDisposable вызывается dispose при выходе из using. Где нужно управлять ресурсами этого хватает за глаза.
                                                                                                                            –2
                                                                                                                            Вообще то к примеру хэндл окна (даже упрятанный под кучу оберток) или видеопамять это такой же ресурс. Они у вас типа не разу не долгоживущими объектами каким то образом стали? А файлы? А косвенно владеемые ресурсы? из Dispose ручками высвобождаете? Зачем GC нужен если нужно все равно по дереву удаляемых проходить вручную всегда а то беда беда будет? И чем ручное написание using отличается от ручного вызова delete? Автоматика где?
                                                                                                                            И это вопросы не языка. Это вопросы обеспечения деинициализации объектов по правилам ООП, которые не зависят от языка. Абсолютно очевидно что GC абсолютно бесполезен для имплементации этих правил. Потому что предназначен для решения абсолютно противоположной задачи. При этом имплементация этих правил делает GC абсолютно ненужным, потому что аналогична вызову GC.Collect после каждого изменения ссылки, при этом гораздо эффективнее GC, поскольку не имеет постоянных накладных расходов на содержание живых, только на вынос мертвых который необходимо производить и при наличии GC.
                                                                                                                              0
                                                                                                                              Ваш бред в голове сложно комментировать.

                                                                                                                              Давайте сначала вы ответите на вопрос. Сколько кода в продакшн вы непосредственно написали и когда последний раз это было?
                                                                                                                                –1
                                                                                                                                Ваш бред в голове сложно комментировать.
                                                                                                                                Когда вы крайний раз правила по которым ООП функциклит в голове освежали? Вы с ними вообще знакомы? А теорию графов изучали? А анализ графов взаимосвязей в вашей задаче когда призоводите до написания кода или после? А то вы похоже вообще просто не в теме что такое ООП и чем задачи управления памятью отличается от задачи управления жизненым циклом и задачи управления взаимосвязями.
                                                                                                                                  +2
                                                                                                                                  Вы знаете, я код пишу в прод, а не читаю мистические правила времен советских вузов.
                                                                                                                                    –3
                                                                                                                                    Вы знаете, я код пишу в прод, а не читаю мистические правила времен советских вузов.

                                                                                                                                    Вообще то человек который анализирует задачу описывает ее в терминах той или иной методологии проектировани и потом реализует ее в коде называется инженер-программист.
                                                                                                                                    А вот те которые академиев не кончали и сначала на клавиши жамкают те не код в продакшин пишут а баги быдлокодят.
                                                                                                                                      +1
                                                                                                                                      На всякий случай, вы разговариваете с к.т.н. по 05.13.06.
                                                                                                                                      Поэтому поверьте, я в программирование как теоретически, так и практически разбираюсь лучше вашего.

                                                                                                                                      И поверьте человеку, который 14 лет пишет код в продакшн, а не блокчей очередной юзает: ваши представления о программировании лютейший ТРЭШ.
                                                                                                                                        –3
                                                                                                                                        Поэтому поверьте, я в программирование как теоретически, так и практически разбираюсь лучше вашего.
                                                                                                                                        От это крутые к.т.н пошли которые с моделью акторов не знакомы.
                                                                                                                                        И поверьте человеку, который 14 лет пишет код в продакшн
                                                                                                                                        т.е. до уровня проектирования системы по научным методика с последующей реализацией ее в коде даже за 14 лет не доросли? Вот потому вам и некогда — вынуждены постоянно обкостыливать грабли которые сами же и заложили.
                                                                                                                                          +1
                                                                                                                                          Я не знаю что у вас за образование, и есть ли оно вообще, факт что читать вы так и не научились. Потому что вы оппонируете на какие-то вещи которые сами и придумали. А для .Net есть Akka, если уж вам так интересно.

                                                                                                                                          В реальном мире системы проектируется не по научным методикам, а по бизнес методикам, потому что ЗП платит бизнес. Вы можете сказать бизнесу, что вы создаете гениальный фундаментальный фреймворк на Си, поэтому ваша задача будет решена через 5 лет. Но я уверен, что очень быстро вы отправитесь на мороз.

                                                                                                                                          Спорить тут абсолютно бесполезно, потому что очевидно, что вы не разрабатывали софт для/в коммерческих компаний. Пока нет примеров ваших Гениальных проектов с научными методиками, спорить можно прекращать.
                                                                                                                            +1
                                                                                                                            GC этого не умеет от слова совсем.

                                                                                                                            GC этого не должен уметь по определению. Память не является тем ресурсом, который должен быть обязательно освобождён по выходу из scope. А что должно быть освобождено обязательно — освобождается явно. Сейчас даже scope-based using добавили, чтобы сделать это ещё более удобным.


                                                                                                                            Я про автоматическое управление жизненным циклом. Про автоматическую деинициализацию объекта при выходе его из скопа/деинициализации содержащего его объекта.

                                                                                                                            При программировании многопоточных приложений на C++ я на практике сталкивался с ситуациями, когда подобное поведение оказывалось нежелательным, а управление памятью становилось весьма сложным и тяжёлым с нагромождением shared_ptr/weak_ptr и проблемами с циклическими зависимостями. В C# же такой проблемы нет.

                                                                                                                              –3
                                                                                                                              а управление памятью становилось весьма сложным и тяжёлым с нагромождением shared_ptr/weak_ptr и проблемами с циклическими зависимостями.

                                                                                                                              ООП не пробовали использовать? В нем проблем с циклическими зависимостями нет.
                                                                                                                                +1

                                                                                                                                А причём тут ООП? Ну вот есть два объекта, каждый из которых ссылается на другой. Они сами не удалятся.

                                                                                                                                  –3
                                                                                                                                  А причём тут ООП? Ну вот есть два объекта, каждый из которых ссылается на другой. Они сами не удалятся.

                                                                                                                                  Ну дак это уже нарушение правил предметной области. Т.е. сама такая ситуация это уже баг. Потому что деинициализация объектов в таком случае не может быть произведена вовремя. Поэтому правила построения связей такую ситуацию полностью исключают.
                                                                                                                                  В ООП нет понятия нужен/не нужен. Есть понятие может/не может продолжать существование. При этом одной из причин невозможности продолжать существование есть разрыв связи типа копозиция. Т.е. нет препятсвующих удалению. Есть ответсвенные за удаление которые удаляют вместе с собой объекты на которые ссылаются. И смена ответсвенного невозможна, он назначается при создании. А соответсвенно и образоваие такого кольца тоже. При разрыве внешней связи произойдет уничтожение обоих объектов.
                                                                                                                                    +2
                                                                                                                                    Ну дак это уже нарушение правил предметной области. Т.е. сама такая ситуация это уже баг. Потому что деинициализация объектов в таком случае не может быть произведена вовремя. Поэтому правила построения связей такую ситуацию полностью исключают.

                                                                                                                                    Извините меня но что за чушь вы тут несёте? Два обьекта с ссылками друг на друга встречаются в любом ООП языке сплошь и рядом и никаким багом не являются.
                                                                                                                                    Да возьмите любое банальное parent<->сhild отношение и вот вам уже пример такой пары.

                                                                                                                                      +2
                                                                                                                                      Двухсвязанный список же.
                                                                                                                                        –5
                                                                                                                                        Извините меня но что за чушь вы тут несёте?
                                                                                                                                        То просто вы не въехали в суть того как это работает в ООП. чилд композирован в парента. т.е он не может существовать без парента. Разрыв этой ссылки приводит к мгновенному и перманентному уничтожению чилда. Кстати так о птичках это не циклическая а двунаправленная ссылка. И по сути в ООП все ссылки двунаправлены. И никакие счетчики не нужны.
                                                                                                                                        Два обьекта с ссылками друг на друга встречаются в любом ООП языке сплошь и рядом и никаким багом не являются.

                                                                                                                                        Багом они станут если оторвутся. Т.е. если дед потеряет ссылку на парента. Но поскольку потертеря этой ссылки по правилам то й же композиции ведет к перманентному удалению парента то и парент и чилд тут же будут удалены.
                                                                                                                                        Вот так кстати все и фурычит в той же дельфе. Все на таких двунаправленных ссылках. И именно это обеспечивает возможности широкого использования биндинга и как следствие преимущественно визуальной разработки бизнеслогики

                                                                                                                                          +1
                                                                                                                                          То просто вы не въехали в суть того как это работает в ООП. чилд композирован в парента. т.е он не может существовать без парента. Разрыв этой ссылки приводит к мгновенному и перманентному уничтожению чилда

                                                                                                                                          И снова какой-то бред. У меня совершенно спокойно могут быть ещё и отдельные ссылки на пэрента и на чайлда. Но вот если я их уберу и оставлю только их ссылки на друг друга, то по вашей логике они навсегда останутся в памяти....


                                                                                                                                          Багом они станут если оторвутся.

                                                                                                                                          Происходит сплошь и рядом. Вполне себе умышленно и тоже никаким багом не является…

                                                                                                                                            –2
                                                                                                                                            И снова какой-то бред. У меня совершенно спокойно могут быть ещё и отдельные ссылки на пэрента и на чайлда. Но вот если я их уберу и оставлю только их ссылки на друг друга, то по вашей логике они навсегда останутся в памяти....
                                                                                                                                            А теперь представьте что они все двунаправленные. Т.е. объект при уничтожении обнуляет/вычищает из контейнеров все оставшиеся на него ссылки.
                                                                                                                                              0

                                                                                                                                              То есть объект кто-то уничтожает вручную. Где же премущество автоматического управления ресурсами?

                                                                                                                                              –3
                                                                                                                                              Ну вот поэтому то что с GС раньше или позже начинает течь как минимум ресурсами а то и косвенными утечками. Потому что объекты не деинициализируются как это предписывают делать правила ООП.
                                                                                                                                                +2

                                                                                                                                                Опять какие-то ваши фантазии и абсолютное непонимание того как работает GC. GC в такой ситуации совершенно спокойно убирает оба объекта.

                                                                                                                                                  –2
                                                                                                                                                  в такой ситуации совершенно спокойно убирает оба объекта.
                                                                                                                                                  GC уберет буфера памяти занимаемые объектами, а не объекты. Он вообще объектами не управляет, только буферами памяти. При этом вопрос наличия сторонней ссылки на объекты точно так же придется разруливать и при использовании GC, у которого при наличии такой дополнительной ссылки с альтернативной трассой на рут и происходит коственная утечка. Решается это опять же или ограниченым по функциональности частным случаем со слабыой ссылкой, либо общим случаем с двунаправленно связью с инстантным оповещением ссылающегося.
                                                                                                                                                  Т.е. вопрос с необходимостью в слабых ссылка опять же не из языка и способа управления памятью растет, а из правил ООП которые предусматриваю два типа связей — композицию и агрегацию. При этом поведение жестких ссылок с GC перевернуто по сравнению с композицией на 180 градусов, а несвоевременная и даже негарантированная деинициализация объектов и является причиной несоответсвия модели акторов, что и является причиной всех граблей. Имплементровать же в автоматическое поведение ссылок в соответствии с моделью акторов GC не может от слова совсем, в отличии от современной автоматики, потому что разрабатывался в 1959-ом и предназачнен для управления пассивными буферами памяти, а не активными моделями сущностей предметной области, которыми являются объекты в терминах ООП.
                                                                                                                                                    +4

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

                                                                                                                                    –2
                                                                                                                                    Память не является тем ресурсом, который должен быть обязательно освобождён по выходу из scope
                                                                                                                                    А инстанс который живет в этой памяти должен быть деинициализирован обязательно. Опять же по правилам ООП. Поэтому придется по дереву удаляемых пройти все равно. И гораздо эффективней попутно и буфера в список неиспользуемых занести пока знаем какие, чтобы не сканировать постоянно всех живых.
                                                                                                                                      +1
                                                                                                                                      А инстанс который живет в этой памяти должен быть деинициализирован обязательно

                                                                                                                                      Совершенно не обязательно, если единственный используемый ресурс — это память.


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

                                                                                                                                      Не факт. Удаление из глобальной кучи вотпрямщас дорогое + требуется межпоточная синхронизация.

                                                                                                                                        –2
                                                                                                                                        Совершенно не обязательно, если единственный используемый ресурс — это память

                                                                                                                                        А откуда вы знаете какой там ресурс под капотом и какая там вообще под ним глубина дерева композиции объектов и какие агрегации у этого поддерева нужно разорвать при деинициализации? В общем случае об этом знает только сам объект. Именно поэтому и требуется деинициализация всего удаляемого подерева.
                                                                                                                                          +2

                                                                                                                                          Об этом говорит наличие интерфейса IDisposable и намерения программиста по явной очистке ресурсов.

                                                                                                                                            –3
                                                                                                                                            Об этом говорит наличие интерфейса IDisposable
                                                                                                                                            Так он у всех абстрактных базовых типов должен быть. Потому как абстрактный предок не может знать что будет под капотом у потомков. А обрабатывается то оный потомок по ссылке на предка.
                                                                                                                                              –3
                                                                                                                                              и намерения программиста по явной очистке ресурсов

                                                                                                                                              20-ый год 21-го века. А все ручками делать. В том числе Dispose писать. Не я с такими глупостями еще в прошлом тысячелетии покончил. намучался достаточно на паскакале. Т.е. никакой разницы с полным отсутствием автоматики GC не дает кроме ненужного оверхеда.
                                                                                                                                                0
                                                                                                                                                Dispose ничего общего с GC в общем случае не имеет, и в большинстве не системных классах используется для иных целей.
                                                                                                                                                Dispose используют для очистки ресурсов только когда надо освобождать неуправляему память, например при работе напрямую с DLL.
                                                                                                                                                Но в реальности (продакшене) это используется как обычный метод который будет вызываться в using, с помощью него можно писать, например, структурные логи.
                                                                                                                                                using(Log.Header())
                                                                                                                                                using(Log.Body())
                                                                                                                                                Для managed ресурсов явное написание Dispose вообще не имеет смысла.