MemoryMarshal.AsRef Метод
AsRef<T>(Span<Byte>)
Повторно интерпретирует массив байтов как ссылку на структуру типа T.
Копировать
public static ref T AsRef<T> (Span<byte> span) where T : struct;
Параметры типа
T
Тип возвращаемой ссылки.
Параметры
span
Span<Byte>
Повторно интерпретируемая массив.
Возвращаемое значение
T
Ссылка на структуру типа T.
Комментарии
T не может содержать указатели или ссылки. Он проверяется во время выполнения, чтобы обеспечить безопасность типа.
и солнце б утром не вставало, когда бы не было меня
Re[50]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, vdimas, Вы писали:
V>>>И в любом случае твой пример только для MSSQL, а для любых других баз на основе OLEDB или ODBC НС>>И много таких баз данных в реальности? V>А много используют MSSQL в вебе?
Много. В Ажуре, к примеру, это основная РСУБД. К чему вопрос?
V>>>Разве что написали дотнетный драйвер к MS SQL, изначально это была обычная обёртка над OLEDB, НС>>Никогда не была. Изначално это была обертка над низкоуровневоцй библиотекой парсинга протокола (tdslib.dll или как то так). V>Над MS SQL Native Client.
Вроде того. Это не ADO, это более низкоуровневая штука.
V>В котором доступны были 3 вида подключения — ODBC, OLEDB и еще не помню название вида подключения
Нет. Конкретно та либа — обычная плоская dll со специфичным контрактом, по сути просто парсер TDS. ODBC и OLEDB драйвера сами ее используют, а не являются ее частью.
НС>>Хинты, как показывает практика, нужны хорошо если в 1% запросов. Это почему DAL не стоит затачивать под конкретного провайдера. V>Как показывает практика, 1% запросов используется в 99% случаев.
Это неважно. Потому что 1% запросов это 1% кода, и проще сделать для 1% специальное исключение, а не переписывать ради этого под каждый сервер оставшиеся 99%.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[50]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, vdimas, Вы писали:
V>Куда я тебе показал в первый раз — это реализация ODBC драйвера. V>Все базы имеют ODBC-дрова, но далеко не все имеют OLEDB. V>Например, нет OLEDB драйвера к самой популярной в вебе базе MySQL. V>Следующая по популярности идёт PostgreSQL, к ней тоже живые/актуальные только ODBC-дрова.
Опять за рыбу деньги. ADO.NET драйвера и к MySQL, и к Postgres — полностью managed, не используют ни ODBC, ни OLEDB, ни вообще какую либо внешнюю библиотеку. Я сейчас вообще затрудняюсь придумать хоть одну БД, где бы ODBC или OLEDB мост был бы единственным выбором в силу отсутствия pure драйвера.
V>Для MS Access! ))
О, точно. Есть такое.
V>То бишь, самим реализовать всё семейство с 0-ля: IDbConnection, IDbTransaction, IDbCommand и еще пару десятков (если не больше) сущностей из модели ADO.Net.
Не пару десятков, меньше. Да, так и делают на практике. Но есть еще драйвера для EF (их, правда, далеко не все делают).
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[44]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, vdimas, Вы писали:
V>Хотя, подозреваю, что быстродействие вызова UnmanagedCallersOnly-метода должно быть примерно на уровне DllImport.
Ну, с практической точки зрения там почти всё — бессмысленно. Вот эти все "давайте получим анменеджед указатель на менеджед делегат, и вызовем его из менеджед кода" — нулевая практическая ценность.
Удивительно то, что вызов через делегат, ещё недавно чуть ли не на порядок проигрывавший вызову через интерфейс, теперь сравнялся — у меня делегат вышел даже быстрее.
В общем, предсказуемым образом, менеджед код быстрее всего вызывать через managed func pointer, а анменеджед — через PInvoke без переключения GC.
Method
m
Mean
Error
StdDev
Median
Overhead Ratio
CallTest
Baseline
173.9 μs
3.44 μs
9.37 μs
173.2 μs
0%
CallTest
Managed func ptr
245.1 μs
3.37 μs
2.63 μs
244.9 μs
100%
CallTest
Delegate from MI
335.8 μs
3.94 μs
3.29 μs
336.2 μs
227%
CallTest
Delegate
339.1 μs
6.72 μs
13.57 μs
337.5 μs
232%
CallTest
Interface
371.3 μs
7.32 μs
14.10 μs
368.6 μs
277%
CallTest
DllImportNGC
399.2 μs
7.98 μs
18.50 μs
392.3 μs
316%
CallTest
DllImport
901.5 μs
14.52 μs
12.12 μs
896.8 μs
1022%
CallTest
DllGetProcAddr
950.6 μs
18.98 μs
39.61 μs
935.4 μs
1091%
CallTest
Ptr from delegate
1,572.6 μs
19.71 μs
21.91 μs
1,564.2 μs
1964%
CallTest
Unmanaged func ptr
8,796.0 μs
174.14 μs
232.47 μs
8,690.9 μs
12110%
CallTest
Delegate from ptr
10,214.0 μs
158.16 μs
231.83 μs
10,140.2 μs
14101%
Самый дешёвый вызов — по менеджед указателю — на моём процессоре стоит 7ns. Вызов через делегат — 16ns, в 2.3 раза дороже. Примерно в том же классе вызов через интерфейс.
Вызов простого PInvoke, который сам быстро исполняется и не лезет в менеджед-данные, стоит 22.5ns — втрое дороже, чем менеджед вызов, но всё ещё в 2.5 раза дешевле, чем обычный PInvoke через DllImport или через GetProcAddress. (73 ns). Вызовы менеджед кода как анменеджед стоят космически дорого (1мкс), но они и не нужны. Более жизненным сценарием было бы замерить вызов менеджед кода через колбэк.
Но и там основное, для чего нужно такое измерение — это чтобы понимать, какими должны быть масштабы объёма нативной работы, чтобы взаимодействие с ней было оправданым.
То есть когда мы говорим "вот тебе десять мегов данных, позови меня, когда отправишь" — это норм. А когда мы говорим: "вот тебе массив из 100 менеджед указателей, давай ты его отсортируешь, вызывая вот этот колбек для сравнения каждого из них" — это не норм, не надо так делать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vfedosov, Вы писали:
V>Ну вот к примеру +- типичная задача: нужно развернуть индекс: есть индекс по одному ключу, надо построить по другому. В пайтоне решается так: V>names2data = {"name1": (1, 3, "str1"), "name2": (2, 4, "str2")} V>data2names = {data[1]: name for name, data in names2data.items()}
Не очень понимаю синтаксис — что делает эта штука? V>я не в курсе, может последние версии шарпа позволяют коротко эту задачу решить — уж лет 6-7 не работаю с шарпом, но пайтон и 10 лет назад это поддерживал. Насколько кратко можно проинициализировать сложную структуру данных и насколько легко с ней работать! Кстати работает мега быстро в отличии от довольно медленного Linq.
V>Или обработка массивов float — работает почти как на плюсах по скорости. Имеем двумерный numpy массив — картинку (яркости пикселей нормированы к 1.0), надо сделать ярче в 1.5 раза, но значения не должны быть больше 1.0: V>array_2d = np.min(array_2d * 1.5, 1.0) V>Может слегка с синтаксисом в примерах накосячил (влом проверять) — но суть такая. V>Представь чего на шарпе придется нагородить для этого
Ну, вот я себе хорошо это представляю.
array_2d = (from a in array_2d select Math.Min(a*1.5, 1.0)).ToArray();
https://github.com/evilguest/linq2d V>и сколько это работать будет по времени.
Ну, некоторые вещи работают быстрее, чем на плюсах. Может быть, numpy написан получше — можем помериться, если есть желание. V>Работа с массивами в numpy вообще впечатляет — очень элегантно. Занимаясь имадж процессингом, я понял, что плюсы не нужны почти нигде — все можно сделать на пайтоне — и не будет тормозить! V>На шарпе это невозможно.
Вы недооцениваете шарп.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[42]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, vdimas, Вы писали:
V>Это следствие невозможности боксирования. V>Следствие невозможности располагаться в полях не ref-struct типов.
Я в курсе — но, тем не менее, ограничение такое есть.
V>Не обязательно ограничена интеропом, просто хорошо подходит как доп. искуственно-вводимые разработчиком ограничения через систему типов. V>Для пущей безопасности, кароч, чтобы временные ссылки никуда случайно не утекли.
Ну так в том-то и дело, что не так много случаев, когда в гражданском коде мы будем пользоваться вот такой вот структурой "ограниченного действия".
V>Случаев сразу несколько. V>Раньше был доступен stackalloc только под примитивные blit-типы. V>Например, делаешь byte * b = stackallock byte[N], затем приводишь к указателю на структуру. V>Потом стало можно привести к управляемой ref-ссылке на структуру через CompilerServices.Unsafe. V>В последней версии C# можно делать stackalloc пользовательских структур, которые вдоль всей иерархии агрегации состоят или из простых типов или структур, состоящих из простых типов. V>Т.е. структуры, попадающие под ограничение unmanaged. V>В т.ч. в теле которых располагаются inplace-массивы примитивных типов или тоже unmanaged структур.
Ага, вы говорите про "массивы структур". Но ведь с ними и до этого особенных проблем не было — ну, разве что, кроме случаев, когда сама структура не нужна за пределами текущего фрейма стека, и не хочется нагружать GC.
Я-то имел в виду работу с flexible array member https://en.wikipedia.org/wiki/Flexible_array_member
V>>>Чтобы GC игнорировал стек нейтивных вызовов. V>>>Т.е., возможна зебра вглубь всех вызовов: V>>>- из управляемого кода в нейтив; V>>>- оттуда приходит колбэк в управляемый код (многие перечисления в системных АПИ так работают); V>>>- из этого фрейма опять вызывается что-то в нейтиве. S>>Ну в вашем-то случае весь метод — это инкремент лонга по указателю. Никаких колбэков, никаких зебр.
V>У меня просто бенчмарк различных способов вызова ф-ий. V>А ты спрашивал, зачем замыкается стек перед вызовом нейтивной функциональности. V>А как GC должен знать, где в стеке управляемые данные, а где игнорить?
Программист ему подскажет, где можно безопасно игнорить, при помощи SuppressGCTransition.
V>Стек замыкается в любом случае, т.к. GC stop world никто не отменял.
Для конкретного метода с инкрементом отключение GC Transition ускоряет вызов в натив вдвое. Если вычитать baseline — то втрое.
Для часто вызываемых микро-методов типа "набъём команды в буфер" — самое то.
V>Средней руки приложение может компиляться под AOT iOS несколько минут, сколько-нибудь большое — десятки минут. V>Поэтому, всё это херня собачья, гнаться за хотспотом.
Не уверен.
V>Над разрабывать либы так, чтобы они были готовы к нейтивной компиляции потом, а клиент при публикации своего приложения пусть запускает АОТ-оптимизатор.
V>Ну, у нас зато тоже в некоторых проектах тонны статического-справочного кода, вот на такх проектах разница видна хорошо. V>И что характерно — если эти "справочные" данные бинарно сериализовать (не встроенной бинарной сериализацией, которой теперь тоже нет в .Net Core, а просто ручками), сохранить в ресурсах, а потом при старте прочесть — это занимает примерно 30 ms. А в исходном виде добавляло примерно 400 ms.
Непонятно, откуда тормоза.
S>>Это для десктопа. А для любимого мной бэкенда важен именно хотспот, т.к. никакой AOT не предскажет реальную нагрузку. V>А толку, если нагрузка может меняться?
Ну так для того хотспот в джаве и умеет повторно джиттить уже отджиттенный код. Нагрузка поменялась => метод перекомпилировали. V>В нейтиве для этого отродясь было PGO. V>К АОТ его тоже надо прикручивать.
У PGO ровно та же самая проблема — устаревание данных.
V>Хотя, АОТ хорош тем, что не рассматривает типы как открытые, хотя бы по виртуальности/наследованию.
Это как это он так не рассматривает? А если я динамически код сгенерю? А если будет подгружена новая сборка?
V>Плюс, у него достаточно времени на всевозможные оптимизации.
Для "настольного" применения — согласен, АОТ нужен. А для серверсайда, когда приложение живёт неделями, выделить 1% времени на дооптимизацию даст столько времени, что никакому АОТ столько не дадут. V>Т.е. и дефолтная оптимизация может много чего дать.
Да для начала надо бы, конечно, просто глупостей не делать. Например, всё таки оптимизировать порождаемый IL. V>Просто непонятно — когда это всё будет в наличии! ))
Отож.
V>Просто это был бы не Рослин, а портированный на шарп плюсовый компилятор. V>По моему опыту, портирование кода из С++ в дотнет тривиальное (это обратно нетривиально), у меня получалось портировать примерно 2 тыс строк в день. V>Если хотя бы 4-5 человек навалятся, первый шарповый компилятор на шарпе можно было бы получить примерно за неделю.
Ну ХЗ. Почему-то они так делать не хотели.
V>Просто они вообще с 0-ля его писали. V>Наглухо. V>Похоже, еще и учились писать компилятор в процессе, бгг... V>Заодно похерили ранее сделанные вложения в уже имеющийся компилятор.
V>Детсад, штаны на лямках.
V>Я же почитывал Липперта — он нифига не спец в компиляторостроении. V>Это отдельная дисциплина, не бог весть какая сложная, но в ней надо шарить... V>Желательно, до начала разработки... V>А эти гаврики с шашкой на танк помчались. V>Результат известен.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[38]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Sinclair, Вы писали: V>>>Еще раз, медленно — интероп в C# медленный.
Как оказалось — нет, не медленный. V>>>Требуется сокращать его до минимума. S>>Эмм, а чего там медленного? S>>И, главное, как нода-то ухитряется сделать интероп быстрее?
V>Ноде не надо заботиться о фреймах стека для GC, поэтому, вызывает нейтивные ф-ии напрямую.
Хм. Почему же ноде не надо заботиться о фреймах стека? Она же тоже менеджед и с GC.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, vfedosov, Вы писали:
V>>Ну вот к примеру +- типичная задача: нужно развернуть индекс: есть индекс по одному ключу, надо построить по другому. В пайтоне решается так: V>>names2data = {"name1": (1, 3, "str1"), "name2": (2, 4, "str2")} V>>data2names = {data[1]: name for name, data in names2data.items()} S>Не очень понимаю синтаксис — что делает эта штука?
ну первая строка создает Dictionary<string, (int, int, string)> и заполняет его 2мя элементами. Это индекс — по аналогии с индексами БД — возможность быстро получить данные по имени. Быстро означает за O(ln(n)) или O(1) — полный перебор не канает.
Вторая строка создает новый Dictionary<int, string> — который содержит второй int и key из первого. Это индекс, который позволяет быстро перейти от int к name. Причем после второй строки он уже заполнен и готов к работе. Далее, если в коде тебе нужно получить быстро name для которого второй int = 3, ты пишешь:
name = data2names[3]
V>>я не в курсе, может последние версии шарпа позволяют коротко эту задачу решить — уж лет 6-7 не работаю с шарпом, но пайтон и 10 лет назад это поддерживал. Насколько кратко можно проинициализировать сложную структуру данных и насколько легко с ней работать! Кстати работает мега быстро в отличии от довольно медленного Linq.
V>>Или обработка массивов float — работает почти как на плюсах по скорости. Имеем двумерный numpy массив — картинку (яркости пикселей нормированы к 1.0), надо сделать ярче в 1.5 раза, но значения не должны быть больше 1.0: V>>array_2d = np.min(array_2d * 1.5, 1.0) V>>Может слегка с синтаксисом в примерах накосячил (влом проверять) — но суть такая. V>>Представь чего на шарпе придется нагородить для этого S>Ну, вот я себе хорошо это представляю. S>
S>array_2d = (from a in array_2d select Math.Min(a*1.5, 1.0)).ToArray();
S>
Это ты написал для одномерного массива. Для двумерного это будет сложнее — как раз раза в 3, чем код на пайтоне. А представь, что нужно работать с двумерным массивом RGB пикселей — то есть каждый элемент массива — тоже массив из 3х элементов. Таким образом, массив 3х-мерный. Код на пайтоне будет тот-же, а на шарпе придется дальше разворачивать. S>https://github.com/evilguest/linq2d V>>и сколько это работать будет по времени. S>Ну, некоторые вещи работают быстрее, чем на плюсах. Может быть, numpy написан получше — можем помериться, если есть желание.
Не может этот код быстро работать, так как там виртуальное вызовы IEnumerable идут — причем несколько вызовов на одну итерацию. Шарп не поддерживает inline для подобных вызовов и работает раз в 10-50 медленнее нативного кода в таких случаях — проверено не раз — я не преувеличиваю. При каждом виртуальном вызове идет копирование всех аргументов, создание точки возврата из функции, обращение к виртуальной таблице — куча ненужного дерьма, которое несопоставимо по объему с основной операцией — умножит на 1.5 и сравнить с единицей. Это если обойдется без аллокаций — а шарп иногда преподносит сюрпризы и выполняет аллокации там, где совсем не ожидаешь, начисто убивая производительность. А в пайтоне используется нативная имплементация без всякой виртуальности — все вызовы функций там заинлайнены и алгоритм выполняет только полезную работу — умножить, сравнить, записать результат, передвинуть указатель к следующему значению (если не последнее) — все! Думаю, они там еще и векторные инструкции процессора используют — уж слишком все быстро летает.
V>>Работа с массивами в numpy вообще впечатляет — очень элегантно. Занимаясь имадж процессингом, я понял, что плюсы не нужны почти нигде — все можно сделать на пайтоне — и не будет тормозить! V>>На шарпе это невозможно. S>Вы недооцениваете шарп.
Да я с ним немало поработал в свое время — знаю пределы возможностей. Но я не считаю, что Шарп must die. Как уже писал, Пайтон бесспорно хорош для простых проектов — желательно с одним разработчиком. В команде уже надо очень жестко следить за тем, кто чего пишет. Иначе код быстро станет несопровождабельным. И для проекта со сложной бизнес-логикой и/или сложным UI я бы все еще выбрал Шарп.
Здравствуйте, vfedosov, Вы писали:
V>Занимаясь имадж процессингом, я понял, что плюсы не нужны почти нигде — все можно сделать на пайтоне — и не будет тормозить! На шарпе это невозможно.
Именно поэтому всё для скорости переписывают с Питона или на плюсы для картинок, или вообще на Java/Scala. Если же есть готовая библиотека типа OpenCV, то код на плюсах может быть ещё и компактней, чем на Питоне. И при этом оптимизироваться проще. Так что это всё эфемерность, что Питона достаточно. Узкие места переписывают на плюсы сплошь и рядом, а то и все проекты целиком.
Re[9]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, Sinclair, Вы писали:
V>>>На шарпе это невозможно. S>>Вы недооцениваете шарп.
НС>Ну, с другой стороны это вполне валидная причина не использовать шарп. Он явно лучше знает python/numpy, нежели дотнет с современным шарпом.
С Пайтоном опыта намного меньше чем с Шарпом. С последними версиями действительно не работал, но общий опыт работы с шарпом — лет 6-7. Работал в качестве программиста, архитектора и тим-лида в коммандах на C#. А на Пайтоне иногда простенькие скрипты пишу — день в месяц в среднем. Плюс иногда с нейросетями экспериментирую. Только в последний месяц занялся чем-то посерьезнее — пишу генератор Unit Tests для проекта, ибо отраслевое требование — 100% кода покрывать тестами, а времени на нормальные тесты у нас нет. Вот и выбрал Пайтон, как язык, на котором эту задачу можно решить наиболее эффективно. Код работает быстрее (а это важно — проект колоссальный по объему кода), чем аналогичный на шарпе и синтаксис лаконичнее. Пайтон не разочаровал — тесты генерятся достаточно быстро и код пока вполне сопровождабелен.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Ну, с другой стороны это вполне валидная причина не использовать шарп. Он явно лучше знает python/numpy, нежели дотнет с современным шарпом.
Отож — я и сам большой фанат ignorance-based decision making
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, vfedosov, Вы писали:
V>Здравствуйте, Sinclair, Вы писали:
S>>Здравствуйте, vfedosov, Вы писали:
V>>>Ну вот к примеру +- типичная задача: нужно развернуть индекс: есть индекс по одному ключу, надо построить по другому. В пайтоне решается так: V>>>names2data = {"name1": (1, 3, "str1"), "name2": (2, 4, "str2")} V>>>data2names = {data[1]: name for name, data in names2data.items()} S>>Не очень понимаю синтаксис — что делает эта штука?
V>ну первая строка создает Dictionary<string, (int, int, string)> и заполняет его 2мя элементами. Это индекс — по аналогии с индексами БД — возможность быстро получить данные по имени. Быстро означает за O(ln(n)) или O(1) — полный перебор не канает. V>Вторая строка создает новый Dictionary<int, string> — который содержит второй int и key из первого. Это индекс, который позволяет быстро перейти от int к name. Причем после второй строки он уже заполнен и готов к работе.
А, понятно. data[1]:name — это то, что мы получаем; name, data — переменные итерирования.
Тогда на шарпе это будет так:
var names2data = new Dictionary<string, (int, int, string)>() {["name1"]= (1, 3, "str1"), ["name2"] = (2, 4, "str2")};
var data2names = (from d in names2data select (d.Value.Item2, d.Key)).ToDictionary((t)=>t.Item1, (t)=>t.Key);
Если такого добра будет много, дописываем один раз вот такой однострочник:
public static class TupleEnumerable
{
public static Dictionary<K, V> ToDictionary<K,V>(this IEnumerable<(K,V)> enumerable)
=> enumerable.ToDictionary((t)=>t.Item1, (t)=>t.Item2);
}
И вторая строка превращается в:
var data2names = (from d in names2data select (d.Value.Item2, d.Key)).ToDictionary();
V>Далее, если в коде тебе нужно получить быстро name для которого второй int = 3, ты пишешь:
V>name = data2names[3]
Да, тут всё точно так же. Ну, только читается получше, и компилятор проверяет типы. Ценой, понятное дело, дописывания к инициализациям деклараций вроде Dictionary<string, (int, int, string)>.
V>>>я не в курсе, может последние версии шарпа позволяют коротко эту задачу решить — уж лет 6-7 не работаю с шарпом, но пайтон и 10 лет назад это поддерживал. Насколько кратко можно проинициализировать сложную структуру данных и насколько легко с ней работать! Кстати работает мега быстро в отличии от довольно медленного Linq.
Ну, linq медленный не весь.
V>Это ты написал для одномерного массива. Для двумерного это будет сложнее — как раз раза в 3, чем код на пайтоне.
Нет, я написал для двумерного. V>А представь, что нужно работать с двумерным массивом RGB пикселей — то есть каждый элемент массива — тоже массив из 3х элементов. Таким образом, массив 3х-мерный. Код на пайтоне будет тот-же, а на шарпе придется дальше разворачивать.
Не массив, а структура. Да, там эффективность C# будет не такой впечатляющей — надо допиливать библиотеку. S>>https://github.com/evilguest/linq2d V>Не может этот код быстро работать, так как там виртуальное вызовы IEnumerable идут — причем несколько вызовов на одну итерацию.
Там нет никаких виртуальных вызовов. Генерируется нативный код с векторными инструкциями. Он работает чуть быстрее идиоматического плюсового кода. Сходите по ссылке, почитайте текст, посмотрите видео. V>Да я с ним немало поработал в свое время — знаю пределы возможностей. Но я не считаю, что Шарп must die. Как уже писал, Пайтон бесспорно хорош для простых проектов — желательно с одним разработчиком. В команде уже надо очень жестко следить за тем, кто чего пишет. Иначе код быстро станет несопровождабельным. И для проекта со сложной бизнес-логикой и/или сложным UI я бы все еще выбрал Шарп.
Пределов возможностей шарп не знает никто .
У него очень большой потенциал. И довольно много из него уже реализовано. Именно за это я его и люблю — в отличие от пайтона, мне не нужно переключаться на другой язык для того, чтобы что-то улучшить.
Тот же Linq для IEnumerable написан на том же шарпе, что и использующий его код.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>var names2data = new Dictionary<string, (int, int, string)>() {["name1"]= (1, 3, "str1"), ["name2"] = (2, 4, "str2")}; S>var data2names = (from d in names2data select (d.Value.Item2, d.Key)).ToDictionary((t)=>t.Item1, (t)=>t.Key);
ну ToDictionary() и tuple реально хорошие нововведения — когда я работал на шарпе подобные вещи куда сложнее писать было. Но формально Пайтон всеравно лаконичнее — даже после класса-однострочника. Причем, это старый синтаксис Пайтона — для версий 2.x работает. В простых проектах в одно рыло, типизация не нужна совсем — по крайней мере мне она ничем не помогает. Читабельность подобных пайтоновских конструкций не уступает шарповским — при наличии привычки. Но для сложных и коммандных проектов шарп явно способен что-то предложить.
V>>Это ты написал для одномерного массива. Для двумерного это будет сложнее — как раз раза в 3, чем код на пайтоне. S>Нет, я написал для двумерного.
Ну я попытался на своей VS2013 (более новые версии не доступны в нашей конторе) скомпилять следующий код:
static void test()
{
var array2d = new double[1000, 1000];
array2d = (from a in array2d select Math.Min(a * 1.5, 1.0)).ToArray();
}
ошибка: Error 1 Could not find an implementation of the query pattern for source type 'double[*,*]'. 'Select' not found. Are you missing a reference or a using directive for 'System.Linq'? c:\users\vfedosov\documents\visual studio 2013\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs 30 34 ConsoleApplication2
для одномерного массива вполне компиляется:
static void test()
{
var array2d = new double[1000000];
array2d = (from a in array2d select Math.Min(a * 1.5, 1.0)).ToArray();
}
Чего я и ожидал собственно. Или в новых версия .Net есть "implementation of the query pattern for source type 'double[*,*]'" ? И если есть, то что будет на выходе ToArray() в этом случае? Одномерный массив?
Далее я сделал тест производительности — для одномерного массива. Код на шарпе:
class Program
{
public virtual double[] multiply(double[] array2d)
{
array2d = (from a in array2d select Math.Min(a * 1.5, 1.0)).ToArray();
return array2d;
}
static void Main(string[] args)
{
Program p = new Program();
var array2d = new double[1000000];
for (int i = 0; i < 1000; ++i)
array2d = p.multiply(array2d);
}
вирульный метод введен, чтобы компилятор не попытался оптимизировать ненужный рассчет. Данный код в релизе выполняется более 20 секунд на моем ноуте.
Аналогичный код на Пайтон:
def multiply(arr):
arr = np.minimum(arr*1.5, 1.0)
return arr
array1D = np.ones([1000000], dtype=float)
for i in range(1000):
array1D = multiply(array1D)
выполняется вдвое быстрее даже без компиляции в exe. А нативный код — С++, который делает ту-же работу, выполняется в 5 раз быстрее. В принципе результат шарпа все равно лучше, чем я ожидал — Linq действительно работает более оптимально, чем я ожидал и умудряется избежать какой-то части лишних действий. Но Пайтон быстрее.
S>Пределов возможностей шарп не знает никто .
Это, похоже, правда
Здравствуйте, Nuzhny, Вы писали:
N>Здравствуйте, vfedosov, Вы писали:
V>>Занимаясь имадж процессингом, я понял, что плюсы не нужны почти нигде — все можно сделать на пайтоне — и не будет тормозить! На шарпе это невозможно.
N>Именно поэтому всё для скорости переписывают с Питона или на плюсы для картинок, или вообще на Java/Scala. Если же есть готовая библиотека типа OpenCV, то код на плюсах может быть ещё и компактней, чем на Питоне. И при этом оптимизироваться проще. Так что это всё эфемерность, что Питона достаточно. Узкие места переписывают на плюсы сплошь и рядом, а то и все проекты целиком.
Ну OpenCV доступна на Python — собственно я с ней и работаю в основном. И я бы не сказал, что прям все переписывается на плюсы — иногда приходится — ИМХО где-то треть тасок с имаджпроцессингом приходится писать на плюсах. Иногда и ассемблер нужен — таких тасок процентов 5. Но не Java!. С какой стати на Java код будет работать быстрее?
Насчет компактности OpenCV кода на плюсах тоже неправда. Пайтоновский как минимум не хуже — а ИМХО намного более компактен.
V>Чего я и ожидал собственно. Или в новых версия .Net есть "implementation of the query pattern for source type 'double[*,*]'" ?
Ты всегда можешь написать расширение
public static class TwoDimensionalArrayEnumerable
{
public static IEnumerable<T> ToEnumerable<T>(this T[,] array)
{
for (int i = array.GetLowerBound(0); i <= array.GetUpperBound(0); i++)
{
for (int j = array.GetLowerBound(1); j <= array.GetUpperBound(1); j++)
{
yield return array[i, j];
}
}
}
public static T[,] ToArray<T>(this IEnumerable<T> en, T[,] array)
{
var result = array;//(T[,]) Array.CreateInstance(typeof(T), fub, sub);var elemCount = array.GetUpperBound(1) - array.GetLowerBound(1) + 1;
int ind = 0;
foreach(T elem in en)
{
result[ind / elemCount, ind % elemCount] = elem;
ind++;
}
return result;
}
}
static void TestLinq()
{
var array2d = new double[1000, 1000];
array2d = (from a in array2d.ToEnumerable() select Math.Min(a * 1.5, 1.0)).ToArray(array2d);
}
Есть прекраснейшая конструкция yield на основании которой ты можешь строить любые итераторы.
Для использования как в питоне, нужно просто сконструировать класс который будет держать данные о массиве.
Лениво
и солнце б утром не вставало, когда бы не было меня
Re[12]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, vfedosov, Вы писали:
V>>Чего я и ожидал собственно. Или в новых версия .Net есть "implementation of the query pattern for source type 'double[*,*]'" ?
S>Ты всегда можешь написать расширение S>
S> public static class TwoDimensionalArrayEnumerable
S> {
S> public static IEnumerable<T> ToEnumerable<T>(this T[,] array)
S> {
S> for (int i = array.GetLowerBound(0); i <= array.GetUpperBound(0); i++)
S> {
S> for (int j = array.GetLowerBound(1); j <= array.GetUpperBound(1); j++)
S> {
S> yield return array[i, j];
S> }
S> }
S> }
S> public static T[,] ToArray<T>(this IEnumerable<T> en, T[,] array)
S> {
S> var result = array;//(T[,]) Array.CreateInstance(typeof(T), fub, sub);
S> var elemCount = array.GetUpperBound(1) - array.GetLowerBound(1) + 1;
S> int ind = 0;
S> foreach(T elem in en)
S> {
S> result[ind / elemCount, ind % elemCount] = elem;
S> ind++;
S> }
S> return result;
S> }
S>}
S>
S>
S>static void TestLinq()
S> {
S> var array2d = new double[1000, 1000];
S> array2d = (from a in array2d.ToEnumerable() select Math.Min(a * 1.5, 1.0)).ToArray(array2d);
S> }
S>
S> Есть прекраснейшая конструкция yield на основании которой ты можешь строить любые итераторы. S>Для использования как в питоне, нужно просто сконструировать класс который будет держать данные о массиве. S>Лениво
Вот и мне лениво — поэтому предпочитаю на Пайтоне простые задачи решать. Одна из основных концепций Пайтона — простые вещи должны делаться просто.
Про yield я в курсе. Он и на Пайтоне есть — с точно такой-же функциональностью. Думаю с Пайтона его и собрали в .Net — хотя не уверен.
Re[13]: MS забило на дотнет. Питону - да, сишарпу - нет?
S>> Есть прекраснейшая конструкция yield на основании которой ты можешь строить любые итераторы. S>>Для использования как в питоне, нужно просто сконструировать класс который будет держать данные о массиве. S>>Лениво
V>Вот и мне лениво — поэтому предпочитаю на Пайтоне простые задачи решать. Одна из основных концепций Пайтона — простые вещи должны делаться просто. V>Про yield я в курсе. Он и на Пайтоне есть — с точно такой-же функциональностью. Думаю с Пайтона его и собрали в .Net — хотя не уверен.
На самом деле на шарпе можно решать любые задачи с той же эффективностью. Учитываю, что большинство использует нетипизированный питон, то на шарпе используя
интеллисенс и прочие удобства IDE можно писать даже быстрее.
Это уже дело привычки
и солнце б утром не вставало, когда бы не было меня
Re[14]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, vfedosov, Вы писали:
S>>> Есть прекраснейшая конструкция yield на основании которой ты можешь строить любые итераторы. S>>>Для использования как в питоне, нужно просто сконструировать класс который будет держать данные о массиве. S>>>Лениво
V>>Вот и мне лениво — поэтому предпочитаю на Пайтоне простые задачи решать. Одна из основных концепций Пайтона — простые вещи должны делаться просто. V>>Про yield я в курсе. Он и на Пайтоне есть — с точно такой-же функциональностью. Думаю с Пайтона его и собрали в .Net — хотя не уверен. S>На самом деле на шарпе можно решать любые задачи с той же эффективностью. Учитываю, что большинство использует нетипизированный питон, то на шарпе используя S>интеллисенс и прочие удобства IDE можно писать даже быстрее. S> Это уже дело привычки
Ну давай рассмотрим простую задачу — задание пишу вообще от балды — не подстраивая под Пайтон: открыть файл с именами сотрудников и зарплатами, распарсить все строки и выдать имя наиболее высокооплачиваемого работника. Никакие сторонние библиотеки не используем, как и парсеры CSV — иначе это сравнение библиотек, а не языков. Пример файла:
Иванов, 1000
Петров, 2000
Сидоров, 3000
Для простоты считаем, что все строки содержат корректные записи — ошибки обрабатывать не надо.
На Пайтоне я решу задачу не задумываясь так (наверняка есть решения и еще более лаконичные):
employees = []
for line in open("D:\\test.txt", encoding="utf-8").readlines():
items = line.split(",")
employees.append((items[0], int(items[1])))
employees.sort(key=lambda i: i[1])
print("Employee with the biggest salary is: ", employees[-1][0])
Это полное решение — не нужны никакие import, не нужен проектный файл — это уже готовый к исполнению файл
На C# я буду вынужден нахреначить минимум втрое больше кода и еще и проект создать для этого:
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
public class Program
{
public static void Main()
{
var employes = new List<(string n, int s)>();
foreach(var line in File.ReadAllLines("D:\test.txt", Encoding.UTF8))
{
var items = line.Split(',');
employes.Add((items[0], Int32.Parse(items[1])));
}
employes.Sort((i, j) => i.s.CompareTo(j.s));
Console.WriteLine("Employee with the biggest isalary is: " + employes[employes.Count - 1].n);
}
}
Кроме кучи лишнего кода, связанного с уровнями доступами, декларациями классов, библиотеками, который мне для простого решения вообще не нужен, еще и сам основной код, получился несколько менее компактным и читабельным. В этом коде можно заметить 2 вещи, в которых Пайтон лучше шарпа. Это парсинг строки к int — в Пайтоне делается так: (int) str. Так же сортировки в Пайтоне поудобнее — не нужен компарер — можно задать ключ. Но это мелочи по сравнению с мусорным для простого проекта декларативным кодом.
Здравствуйте, vfedosov, Вы писали:
V>Ну я попытался на своей VS2013 (более новые версии не доступны в нашей конторе) скомпилять следующий код: V>ошибка: Error 1 Could not find an implementation of the query pattern for source type 'double[*,*]'. 'Select' not found. Are you missing a reference or a using directive for 'System.Linq'? c:\users\vfedosov\documents\visual studio 2013\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs 30 34 ConsoleApplication2