Re[77]: Тормознутость и кривость linq
От: IT Россия linq2db.com
Дата: 02.05.16 13:41
Оценка: 4 (2) +1
Здравствуйте, vorona, Вы писали:

IT>>Например, на C# нельзя выразить рекурсивный CTE. Пичалька TABLE и QUERY hints сделали, а до JOIN hint всё руки никак не дойдут.

V>А как на C# можно написать TABLE и QUERY hints?

С TABLE LOCK всё просто.

from p in db.Parent.SchemaName("dbo").With("TABLOCK,UPDLOCK")
select p;


Есть более общая функция, позволяющая задавать выражение для таблицы включая имя, алиас и прочее:

from p in db.Parent.SchemaName("dbo").WithTableExpression("{0} {1} with (UpdLock)")
select p;


QUERY HINT задаётся в виде свободного текста двумя способами для всех последующих запросов до закрытия соединения, либо только для следующего запроса:

using (var db = GetDataContext(context))
{
    db.QueryHints.Add("---");
    db.NextQueryHints.Add("OPTION(RECOMPILE)");
Если нам не помогут, то мы тоже никого не пощадим.
Re[94]: Тормознутость и кривость linq
От: alex_public  
Дата: 02.05.16 15:54
Оценка:
Здравствуйте, IT, Вы писали:

_>>Да, типа того, только большая часть работы происходит на этапе компиляции (метапрограммирование на шаблонах C++). ) Ну и я не автор этой библиотечки, а просто протестировал её для примера.

IT>Понятно. Такие решения мы тоже проходили в своё время и определили их в малопригодные для реальной жизни.

Ну не прямо такие естественно (т.к. C# не поддерживает парадигму метапрограммирования), а видимо построение и исполнение SQL AST в рантайме. А почему посчитали малопригодным?

_>>А как float (да и любой другой тип в C++) по твоему может быть null? )))

IT>Действительно. Т.е. либо потом косяки отлавливать, либо упоротый монструозный код писать.

Ээээ что? )
Re[78]: Тормознутость и кривость linq
От: alex_public  
Дата: 02.05.16 19:14
Оценка:
Здравствуйте, IT, Вы писали:

_>>Я просто с SQL Server дел не имею, так что не особо в курсе что это там такое. Сейчас глянул — это вроде тоже самое, что в других СУБД называют JOIN LATERAL? )

IT>В других это в PostreSQL? Кстати, раньше такого у них не видел. Когда они это добавили? Нужно в linq2db добавить поддержку.

Почему только в PostreSQL? ) Вроде LATERAL и в db2 и в oracle был. Про другие не в курсе, может тоже. )

_>>Например вот эти http://liiw.blogspot.ru/2015/03/performance-of-linq-to-db-vs-entity.html, тебе же их вроде уже показывали тут.

IT>Показывали, потому и не пойму о чём речь. Там вроде ощутимость только у EF. Также там нет тестов CompiledQuery.

Ну вот смотри, берём там тест с названием "Simple TOP 10 query" (думаю что как раз он больше всего похож на большинство запросов в веб'е) и видим, что запрос заданный через linq исполняется в linq2db практически в 2 раза дольше, чем заданный строкой. На мой вкусе это вполне себе существенно.

_>>Ну так это у нас и не высоконагруженный сайт. )))

IT>Да без разницы. Конкретно эта проблема решается не бысрым доступом к БД, а кешированием.

Кешированием чего? Скомпилированных запросов (ты сам писал про трудности с этим) или ты здесь уже про что-то другое?

_>>Нуу большинство СУБД же поддерживают такое. Даже простенький sqlite может. Собственно в тех двух исходниках теста для sqlite были примеры как одного подхода, так и второго. Или мы о разных вещах говорим? )

IT>Видимо мы о чём-то разном. Предкомриляция запроса внутри БД делается самой БД без каких-либо телодвижений с клиента. Если ты о методе Prepare из ADO.NET, то он делается на открытом соединении и держать его открытым между вызовами не самая лучшая идея.

Про ADO.NET я не знаю, я знаю про СУБД и соответствующие методы PREPARE и ЕХЕCUTE в них...

Понятно что СУБД в любом случае будет делать предкомпиляцию и пытаться кэшировать результат. Но очевидно, что прямое указание ссылки на скомпилированный запрос эффективнее.
Re[93]: Тормознутость и кривость linq
От: alex_public  
Дата: 02.05.16 19:32
Оценка:
Здравствуйте, Ikemefula, Вы писали:

_>>А вот как раз этого и не было. Я в этой теме изначально писал только о тормозах Linq ORM и всё. Это оппоненты начали припоминать старые дискуссии и тащить сюда примеры из C++ (в стиле ну и пусть Linq тормозит слегка, но зато он может такое, чего твои C++ решения никогда не смогут).

I>Все ходы записаны. Ты сначала сказал что линк невозможно тормозит и в качестве причины "строить sql строки в рантайме на базе тормознутой рефлексии".
I>То есть, здесь уже замер не относительно узкого места что обычно БД или сеть, а относительно некоего эталона.

Всё верно. И этой базой всегда была реализация той же функциональности на том же языке (т.е. на C# в данном случае) с использованием голых sql строк. C++ и какие-то библиотеки для него я даже не упоминал.
Re[79]: Тормознутость и кривость linq
От: IT Россия linq2db.com
Дата: 02.05.16 19:37
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Почему только в PostreSQL? ) Вроде LATERAL и в db2 и в oracle был. Про другие не в курсе, может тоже. )


В Oracle добавили в 12.1 и LITERAL и APPLY. В DB2 не нашёл.

Кстати, для PostgreSQL вчера добавил поддержку LITERAL. Работает. Спасибо за наводку.

_>Ну вот смотри, берём там тест с названием "Simple TOP 10 query" (думаю что как раз он больше всего похож на большинство запросов в веб'е) и видим, что запрос заданный через linq исполняется в linq2db практически в 2 раза дольше, чем заданный строкой. На мой вкусе это вполне себе существенно.


Надо на код теста посмотреть.

_>Кешированием чего? Скомпилированных запросов (ты сам писал про трудности с этим) или ты здесь уже про что-то другое?


Это решается кешированем результата.

_>Про ADO.NET я не знаю, я знаю про СУБД и соответствующие методы PREPARE и ЕХЕCUTE в них...


Для Prepare как я уже сказал требуется держать открытым соединение. Это неприемлемо.
Если нам не помогут, то мы тоже никого не пощадим.
Re[94]: Тормознутость и кривость linq
От: alex_public  
Дата: 02.05.16 19:53
Оценка:
Здравствуйте, Ikemefula, Вы писали:

_>>А как float (да и любой другой тип в C++) по твоему может быть null? )))

I>А в базе данных — может. Пудозреваю, IT говорит о разнице в SQL. a = b и a is NULL

Да, в БД может и поэтому нужна специальная обработка этого факта при выдаче результатов запроса. В данной библиотечке она естественно есть и даже двумя различными способами. )
Re[95]: Тормознутость и кривость linq
От: IT Россия linq2db.com
Дата: 02.05.16 20:04
Оценка:
Здравствуйте, alex_public, Вы писали:

IT>>Понятно. Такие решения мы тоже проходили в своё время и определили их в малопригодные для реальной жизни.

_>Ну не прямо такие естественно (т.к. C# не поддерживает парадигму метапрограммирования), а видимо построение и исполнение SQL AST в рантайме. А почему посчитали малопригодным?

Наметапрограммировать и в C# можно чего угодно. Особенно в pre-compile time. Что касается малопригодности, то такие решения, чтобы более менее полноценно решать проблемы строгой типизации превращаются в пазлы с триллиардами методов. Обилие вызовов методов в том числе даже для поддержки африфметических операций делает код абсолютно нечитаемым. Достаточно посмотреть на твои примеры — SQL читается легко, а набор методов ужос-ужос. Если на linq народ переходит практически безболезненно, то такие решения чаще всего отторгаются разработчиками из-за малопонятности и более сложной поддержкой чем даже SQL.

_>>>А как float (да и любой другой тип в C++) по твоему может быть null? )))

IT>>Действительно. Т.е. либо потом косяки отлавливать, либо упоротый монструозный код писать.
_>Ээээ что? )

Ты в курсе как работает сравнение в SQL, если один из операндов NULL? Правильно, ты получишь false даже если оба операнда равны NULL. Т.е. чтобы корректно реализовать сравнение нужно его писать не как

Field1 = @p

А в зависимости от значение @p либо

Field1 = @p

либо

Field1 IS NULL

В результате народ не парится и пишет

Field1 IS NULL AND @p IS NULL OR Field1 = @p

Частенько план запроса в таких случаях убивается.
Если нам не помогут, то мы тоже никого не пощадим.
Re[100]: Тормознутость и кривость linq
От: alex_public  
Дата: 02.05.16 20:36
Оценка:
Здравствуйте, Serginio1, Вы писали:

_>>Это всё слова. А тесты показывают другое. Да и не только тесты, но и примеры настоящих специалистов (а не форумных теоретиков), имеющих дело с сильно нагруженными системами.

S> Тесты как раз без AsNoTracking итд. Нужно смотреть где тормоза, а потом их обсуждать. Ты же берешь тесты и делаешь выводы без всякого профилирования, и говоришь о настоящих специалистах?. Есть другие тесты и с другими результатами.

Какое ещё профилирование? Ты так и не понял смысл проведённых тестов? ) Мы не пытаемся измерить какие-то абсолютные цифры и потом сделать их анализ. Мы делаем два отдельных теста на одной и той же ORM, один в режиме sql строк и второй в режиме linq. И соответственно разница между ними априори будет равна накладным расходам от применения linq. Это очевидно даже ребёнку, без всяких профайлеров.

S> Стоит так же сравнить CompiledQuery

S>http://stackoverflow.com/questions/4932594/when-should-i-use-a-compiledquery

Ну так сравни, в чём проблема? Все исходники тестов в наличие. Это мне сложно с ними работать, т.к. у меня не развёрнут стек от MS. А ты же вроде как раз им пользуешься, значит для тебя проблем быть не должно. )
Re[80]: Тормознутость и кривость linq
От: alex_public  
Дата: 02.05.16 21:01
Оценка:
Здравствуйте, IT, Вы писали:

_>>Ну вот смотри, берём там тест с названием "Simple TOP 10 query" (думаю что как раз он больше всего похож на большинство запросов в веб'е) и видим, что запрос заданный через linq исполняется в linq2db практически в 2 раза дольше, чем заданный строкой. На мой вкусе это вполне себе существенно.

IT>Надо на код теста посмотреть.

Там есть исходники по ссылке в начале статьи. )

_>>Кешированием чего? Скомпилированных запросов (ты сам писал про трудности с этим) или ты здесь уже про что-то другое?

IT>Это решается кешированем результата.

Ааа, ну если переходить к таким решениям, то в итоге вообще получится плавных уход от SQL. )))

_>>Про ADO.NET я не знаю, я знаю про СУБД и соответствующие методы PREPARE и ЕХЕCUTE в них...

IT>Для Prepare как я уже сказал требуется держать открытым соединение. Это неприемлемо.

Почему не приемлемо? ) По твоему эффективно делать новое подключение на каждый запрос? )

Ну и да, в любом случае ты уже ответил на мой вопрос. Что прекомпилированные linq запросы включают в себя только подготовку sql строки и не включают работу с СУБД.
Re[96]: Тормознутость и кривость linq
От: alex_public  
Дата: 02.05.16 21:26
Оценка:
Здравствуйте, IT, Вы писали:

_>>Ну не прямо такие естественно (т.к. C# не поддерживает парадигму метапрограммирования), а видимо построение и исполнение SQL AST в рантайме. А почему посчитали малопригодным?

IT>Наметапрограммировать и в C# можно чего угодно. Особенно в pre-compile time.

Если ты имеешь в виду всяческие внешние препроцессоры, то конечно. Только вот это уже будет не C#. Я подобные решения тоже видел (например вот http://www.codesynthesis.com/products/odb/ довольно мощное и популярное), но лично мне они не особо нравятся по целому ряду причин.

IT>Что касается малопригодности, то такие решения, чтобы более менее полноценно решать проблемы строгой типизации превращаются в пазлы с триллиардами методов. Обилие вызовов методов в том числе даже для поддержки африфметических операций делает код абсолютно нечитаемым. Достаточно посмотреть на твои примеры — SQL читается легко, а набор методов ужос-ужос. Если на linq народ переходит практически безболезненно, то такие решения чаще всего отторгаются разработчиками из-за малопонятности и более сложной поддержкой чем даже SQL.


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

_>>Ээээ что? )

IT>Ты в курсе как работает сравнение в SQL, если один из операндов NULL? Правильно, ты получишь false даже если оба операнда равны NULL. Т.е. чтобы корректно реализовать сравнение нужно его писать не как
IT>Field1 = @p
IT>А в зависимости от значение @p либо
IT>Field1 = @p
IT>либо
IT>Field1 IS NULL
IT>В результате народ не парится и пишет
IT>Field1 IS NULL AND @p IS NULL OR Field1 = @p
IT>Частенько план запроса в таких случаях убивается.

Я в курсе. ) Более того, данный вопрос уже подробно обсуждался прямо в этой темке чуть выше. ) И уже был ответ на это, что это довольно странная теория, т.к. при работе скажем на голых строках в том же C# короче записать просто q+=p?"Field1=@p":"Field1 IS NULL"; вместо указанного ужастика. Но опять же это всё не касается случая C++ и той библиотечки, т.к. там вопрос с null просто не стоит. )))
Re[81]: Тормознутость и кривость linq
От: IT Россия linq2db.com
Дата: 03.05.16 01:08
Оценка: +2
Здравствуйте, alex_public, Вы писали:

IT>>Надо на код теста посмотреть.

_>Там есть исходники по ссылке в начале статьи. )

Я понимаю, что они где-нибудь есть. Вопрос в том что надо на них посмотреть

IT>>Это решается кешированем результата.

_>Ааа, ну если переходить к таким решениям, то в итоге вообще получится плавных уход от SQL. )))

А в чём проблема? Нормальное решение. Ты в курсе, что обычно самыми лучшими решениями оказываются гибридные решения? Не? Будешь знать. )

IT>>Для Prepare как я уже сказал требуется держать открытым соединение. Это неприемлемо.

_>Почему не приемлемо? ) По твоему эффективно делать новое подключение на каждый запрос? )

Конечно. Есть такая штука как Connection Pool. Она замечательно решает проблему новых подключений на каждый запрос/группу запросов. Деражать подключение открытым между запросами ради Prepare абсолютно точно плохая идея.

_>Ну и да, в любом случае ты уже ответил на мой вопрос. Что прекомпилированные linq запросы включают в себя только подготовку sql строки и не включают работу с СУБД.


Именно так.
Если нам не помогут, то мы тоже никого не пощадим.
Re[97]: Тормознутость и кривость linq
От: IT Россия linq2db.com
Дата: 03.05.16 01:33
Оценка: +2
Здравствуйте, alex_public, Вы писали:

_>Если ты имеешь в виду всяческие внешние препроцессоры, то конечно. Только вот это уже будет не C#. Я подобные решения тоже видел (например вот http://www.codesynthesis.com/products/odb/ довольно мощное и популярное), но лично мне они не особо нравятся по целому ряду причин.


Мне вообще не нравятся решения, которые генерируют псевдо недо DSL'и. Мы много генерируем, но это может быть, например, модель данных на C#, сгенерированная по метаданным из БД.

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


Так будет выглядеть любое выражение.

_>Сравним так сказать в непосредственной близости. )


Гы-гы. Ты уверен? Я сейчас вытащу на свет какого-нибдуь монстрика и для тебя вечер сразу перестанет быть томным
Лядно, так и быть, что-нибудь попроще. Вот кусочек RSDN'а:

from m in db.Messages
join f in db.AllowedForumsView(Account.ID) on m.ForumID equals f.ID
where
    ids.Contains(m.ID) &&
    m.BlogMessages.All(bm => bm.BlogID != BlogService.Cache.GetBlogID(db, id))
orderby
    m.Subject
select
    m.ID + ", " + m.Subject;


_>Я в курсе. ) Более того, данный вопрос уже подробно обсуждался прямо в этой темке чуть выше. ) И уже был ответ на это, что это довольно странная теория, т.к. при работе скажем на голых строках в том же C# короче записать просто q+=p?"Field1=@p":"Field1 IS NULL";


Ужос. Ты знаешь куда это привело человечество к концу 90-х? К BLL и DAL. Из-за того, что вот практически весь код приложений состоял из вот таких вот испражнений.

_>вместо указанного ужастика. Но опять же это всё не касается случая C++ и той библиотечки, т.к. там вопрос с null просто не стоит. )))


Т.е. глазки закрыли и мы в домике? В C++ нет налов, значит их не должно быть и в базе данных
Если нам не помогут, то мы тоже никого не пощадим.
Отредактировано 03.05.2016 14:04 IT . Предыдущая версия .
Re[95]: Тормознутость и кривость linq
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 03.05.16 04:39
Оценка:
Здравствуйте, alex_public, Вы писали:

_>>>А как float (да и любой другой тип в C++) по твоему может быть null? )))

I>>А в базе данных — может. Пудозреваю, IT говорит о разнице в SQL. a = b и a is NULL

_>Да, в БД может и поэтому нужна специальная обработка этого факта при выдаче результатов запроса. В данной библиотечке она естественно есть и даже двумя различными способами. )


Разумеется, двумя. Потому как в плюсах флоат не может быть null, вот руками и будешь учитывать
Re[96]: Тормознутость и кривость linq
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 03.05.16 05:49
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Разумеется, двумя. Потому как в плюсах флоат не может быть null, вот руками и будешь учитывать


Ну для float вполне годится NULL <-> NaN, и это адекватно и полезно в большинстве случаев.
С обычным int так не сделаешь.

(Чуть в сторону: в KDB+ сделали: у них, например, в int
0x80000000 = NaN(int) (в его обозначениях 0Ni)
0x7fffffff = +INF(int) (0Wi)
0x80000001 = -INF(int) (-0Wi)

но они такими являются только для проверки и для выдачи из функций.
select max(intfield) по пустой выборке даст -0Wi.
Зато 0W+1 == 0N, и конверсия -0Wi к long даст -2147483647 вместо -0Wj
)
The God is real, unless declared integer.
Re[101]: Тормознутость и кривость linq
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 03.05.16 06:01
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Здравствуйте, Serginio1, Вы писали:


_>>>Это всё слова. А тесты показывают другое. Да и не только тесты, но и примеры настоящих специалистов (а не форумных теоретиков), имеющих дело с сильно нагруженными системами.

S>> Тесты как раз без AsNoTracking итд. Нужно смотреть где тормоза, а потом их обсуждать. Ты же берешь тесты и делаешь выводы без всякого профилирования, и говоришь о настоящих специалистах?. Есть другие тесты и с другими результатами.

_>Какое ещё профилирование? Ты так и не понял смысл проведённых тестов? ) Мы не пытаемся измерить какие-то абсолютные цифры и потом сделать их анализ. Мы делаем два отдельных теста на одной и той же ORM, один в режиме sql строк и второй в режиме linq. И соответственно разница между ними априори будет равна накладным расходам от применения linq. Это очевидно даже ребёнку, без всяких профайлеров.

Угу. Я не знаю сколько в этих тестах например занимает компиляция запроса, отображение запроса на модель и тд. Что бы все твои домыслы не были голословными.
S>> Стоит так же сравнить CompiledQuery
S>>http://stackoverflow.com/questions/4932594/when-should-i-use-a-compiledquery

_>Ну так сравни, в чём проблема? Все исходники тестов в наличие. Это мне сложно с ними работать, т.к. у меня не развёрнут стек от MS. А ты же вроде как раз им пользуешься, значит для тебя проблем быть не должно. )

Бремя доказательство домыслов должно лежать на тех, кто эти домыслы распространяет.
Возьмем для примера тесты на которые ты ссылаешься. Чисто технически нет никаких проблем сделать динамически ручной алгоритм.
После выполнения первого запроса можно закэшировать как запрос к базе, так и отображение результата на модель.
Можно использовать DynamicMethods генерируемый через ILGenerator, деревья выражений, а также через компиляцию кода с использованием рослина (Scripting API). То есть основные затраты будут только на первый запрос.
Но большинство запросов именно динамические. Там нужна другая схема
и солнце б утром не вставало, когда бы не было меня
Отредактировано 03.05.2016 6:43 Serginio1 . Предыдущая версия .
Re[99]: Тормознутость и кривость linq
От: Ночной Смотрящий Россия  
Дата: 03.05.16 07:17
Оценка: +1
Здравствуйте, alex_public, Вы писали:

_>Такие фразы надо прямо записывать. Хорошо, сформулирую по другому, для особо одарённых. ) Подскажи мне какая ORM основанная на Linq обходится без рефлексии? )


Ты, как обычно, просто не в теме.
Рассказы о тормозах рефлексии связаны с тем, что через рефлексию примерно на 3 порядка медленнее изменять значения свойств и вызывать методы (сейчас, кстати, там меньше 3 порядков, рассказы про то что за 10 лет ничего не изменилось по твоей ссылке — брехня).
Так вот, нормальный linq провайдер ничего из этого не делает. Скомпилированное компилятором шарпа дерево приложений представляет собой набор вызовов статических методов класса Expression.
Re[101]: Тормознутость и кривость linq
От: Ночной Смотрящий Россия  
Дата: 03.05.16 07:17
Оценка:
Здравствуйте, alex_public, Вы писали:

_>https://github.com/linq2db/linq2db/tree/master/Source/Reflection ага, ага. )))


Этот код выполняется один раз, при первом использовании конкретного типа. Т.е. это тот самый startup performance.
Re[99]: Тормознутость и кривость linq
От: Ночной Смотрящий Россия  
Дата: 03.05.16 07:24
Оценка:
Здравствуйте, alex_public, Вы писали:

_>В третьем случае у тебя в начале код вида if(cond) добавить_в_дерево_выражение(field>cond), а потом где-то в другом месте находится универсальный код обхода дерева (очень тормознутый кстати, причём не по вине разработчиков ORM, а из-за устройства самого .net)


Ты вообще читаешь что тебе пишут? Тебе несколько человек уже сказало — никакой рефлексии при обходе дерева нет. Рефлексия используется для анализа типа, описывающего метаданные самой БД. Этот тип в любом linq провайдере анализируется ровно один раз, при первом обращении, потому что типы в дотнете изменяться не могут.
Re[94]: Тормознутость и кривость linq
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 03.05.16 07:33
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Нуу накидай на C# например скриптик подключающийся параллельно к нескольким удалённым машинам (по ssh), копирующий в них некий проект и собирающий его там. Естественно с выводом всех сообщений об ошибках в локальную консоль. Сравним объём и читаемость твоего решения и решения на Питоне. )


Это весьма неудачный пример. Потому что если у тебя вообще есть библиотека ssh протокола для C#, вроде питоновской paramiko, то перевод логики работы с библиотекой с Питона на C# будет сделан почти автоматически, и из проблем останется только предкомпиляция. Если ты запускаешь ssh в субтерминалах, точно так же будут проблемы в аналоге openpty() (грубо говоря, требуется POSIX, а не Python).

Вот с комбинацией C#+Unix+openpty могут быть проблемы из-за Mono (я лет 5 назад писал, как мы из-под IronPython получили слой неведомой фигни, которая подменяла честные дескрипторы файлов), но это дурость Mono, а не C# самого по себе.
The God is real, unless declared integer.
Re[91]: Тормознутость и кривость linq
От: Ночной Смотрящий Россия  
Дата: 03.05.16 08:48
Оценка:
Здравствуйте, netch80, Вы писали:

N>Мне тут больше непонятно, почему рефлексия такая чудовищно дорогая — миллисекунды.


http://stackoverflow.com/a/3502710/3147269

N>Ну, зачем ты перешёл на рекламу C++ в треде дотнет против явы, отдельный вопрос.


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