• Почему то, что считается преимуществом классов над структурами, иногда выставляется недостатками?

    @footballer Автор вопроса
    lam0x86,
    Анонимные классы возвращать нельзя, поскольку var поддерживают далеко не все языки, работающие под CLR.


    Логично же было делать так: раз кортеж (анонимный объект в круглых скобках) маппится на ValueTuple , то кортеж-класс (анонимный объект в фигурных скобках) должен маппиться на Tuple.
    Ну, или если оставлять анинимные классы, как сейчас они есть, то нужно отдельный синтаксис для классов-кортежей, типа такого
    public static {int sum, int count} GetObjects()
    {
        // res  - это объект по ссылке
        var res =  {sum: 0, count: 0};
        return res ;
    }
  • Непонятное объяснение нового пула потоков в .NET - кто-нибудь может разъяснить?

    @footballer Автор вопроса
    чтобы рабочий поток мог работать с этой локальной очередью без использования блокировк

    Хм, там же в абзаце 2 явно написано, что задачу из локальной очереди одного потока может забрать вообще другой поток:
    Когда рабочий поток видит что делать ему больше нечего, то есть его локальная очередь пустая, он пытается своровать задачу у другого рабочего потока. Но ворует он элементы с хвоста чужой локальной очереди.

    тогда получается, что блокировки все-равно нужны.

    И еще, мой вопрос был в основном про то, что по логике, описанной в абзаце 1, параллельную задачу из своей локальной очереди будет выполнять тот же поток, который запустил ее, то есть, никакого параллелизма и не будет (если я правильно понял). Вот пример:
    // эта функция выполняется в потоке #1
    void DoSmth()
    {
        Task.Run(
            // этот делегат выполняется тоже в потоке #1 и только после того, как поток полностью завершит тяжелые вычисления в DoHeavyCalculations
            x => CallNetworkService()
        );
        DoHeavyCalculations();
    }

    То есть, в этом случае запрос на сетевой сервис уйдет не сразу, а после большого промежутка времени (пока не выполнится DoHeavyCalculations). Это равноценно тому, что мы просто напишем однопоточный код так:
    // эта функция выполняется в потоке #1
    void DoSmth()
    {
        DoHeavyCalculations();
        CallNetworkService();
    }

    И еще более не понятно, а что будет в случае, если есть еще другая функция, которая зависит от результата сетевого запроса. Вот пример:
    void DoSmth()
    {
        Task<int> networkTask = Task.Run(
            // этот делегат выполняется тоже в потоке #1 и только после того, как поток полностью завершит тяжелые вычисления в DoHeavyCalculations и в DoSmthWithInteger, но DoSmthWithInteger никогда не завершится, т.к. зависит от вызова GetIntegerFromNetworkService (получается взаимная блокировка).
            x => {return GetIntegerFromNetworkService();}
        );
        DoHeavyCalculations();
        // невозможно вызвать DoSmthWithInteger, потому что мы никогда не получим значение networkTask.Result
        DoSmthWithInteger(networkTask.Result);
    }

    Вэтом случае одна задача зависит от результатов другой, но так как обе задачи должны быть запущены одним потоком, то код никогда не сможет выполниться. Можно предположить, что в этом случае вторую задачу принудительно отдадут другому потоку, но в той статье об этом же ничего не написано, отсюда и не понятно ничего и вызывает вопросы.
    Но опять таки, раз задача из локальной очереди одного потока будет принудительно отдаваться другому потоку, то все-равно нужны блокировки, то есть отличий в поведении от старого пула и не должно быть.
  • Есть ли преимущество от выполнения задачи в двух потоках на одном ядре?

    @footballer Автор вопроса
    По-моему, 1-й вариант будет быстрее, так как не будет тратиться время на переключение контекста. Так что преимущества может не быть, если говорить о некой абстрактной вычислительной задаче.


    Вот тут https://habrahabr.ru/post/109705/ в комменте пишут:
    У сервера есть 1000 клиентов и на каждого из них при его запросе будет открыватся асинхронная операция — либо паралельные вычисления либо I/O. И мы очень легко получим это «исчерпение». Но для такого сервера нужно лимитировать число одновременных клиентов для которых запускаются асинхронные операции. Т.е. для 1000 клиентов к примеру открываем, остальные будут ждать.

    Для чего выполнять параллельные вычисления в 1000 параллельных потоках, если проц 1-2-х ядерный? Вы же вот выше написали, что в вычислительных задачах преимущества может не быть. Почему тогда юзер в том комменте пишет про то, что нужно лимитировать именно 1000, а не кол-вом ядер?
    Или он еще пишет про I/O , но ведь чтение данных жестким диском всегда последовательное, то есть нельзя одновременно читать данные с двух мест. Снова не вижу смысла открывать 1000 потоков на I/O (чтение\запись на диск).
  • Есть ли преимущество от выполнения задачи в двух потоках на одном ядре?

    @footballer Автор вопроса
    sim3x,
    Если они будут в одном, то даже если поток имеет данные он не может начать работу пока другой не закончит свою


    но получается, что если есть третий поток, пусть даже запущенный другим процессом, и третий поток выполняет тяжелую операцию и долго жрет проц на 100%, то тут не имеет смысла моей проге запускать 2 параллельных потока на ожидание данных? Потому что несмотря на то, что второй поток (вторая задача) может получить данные раньше первой и сможет обработать данные, не ожидая конца первой задачи, в этом случае второй поток создаст конкуренцию третьему, что в итоге замедлит и второй, и третий? Т.е. в этом случае лучше даже обе мои задачи на ожидание данных запускать последовательно, чтобы не создавать конкуренцию и задержки на переключения потоков? Но почему тогда нет такого паттерна при работе с многопоточностью, типа сначала проверять текущую загрузку проца, а потом уже решать, запускать задачу в отдельном потоке или в том же?
  • Есть ли преимущество от выполнения задачи в двух потоках на одном ядре?

    @footballer Автор вопроса
    Роман,
    Попробуйте написать 2 бесконечных цикла и запустить их в 2 потока на одном ядре)

    что это должно показать?
  • Есть ли преимущество от выполнения задачи в двух потоках на одном ядре?

    @footballer Автор вопроса
    sim3x,
    >Задачи, которые в основном ждут данных, - имеет смысл

    Объясните, как на низком уровне потоки "ждут данных". И почему много потоков, запущенных на "ждание данных", всегда лучше и быстрее, чем если бы все ждали данные в одном потоке.
  • Есть ли преимущество от выполнения задачи в двух потоках на одном ядре?

    @footballer Автор вопроса
    Вообще, в начале этого века почти все компы были одноядерными. Но программы уже были многопоточными (в диспетчере задач вин хр можно было увидеть кол-во потоков, создаваемых процессами, многие процессы создавали кучу потоков, для чего?).
    Или вот, например, я пишу прогу на C# WCF, запускаю несколько сервисов, каждый из них создает себе отдельный поток, кроме этого еще какие-то дополнительные потоки возникают (в окне Threads показывается потоков даже больше, чем сервисов), в итоге у меня прога запускает кучу потоков. Для чего запускать кучу потоков, если у меня двухядерный проц?
    Я понимаю, когда второй поток нужен, чтобы запускать код, который обрабатывает движение мыши, чтобы была возможность отлавливать клики и т.п., а в фоне что-то полезное рассчитывать. Но в WCF-проекте на моем двухъядерном проце все-равно больше двух потоков одновременно не выполнятся, и даже если куча клиентов одновременно запросят все мои сервисы, то их код не будет выполняться параллельно, а просто выполнение одного будет прерываться выполнением другого и т.д., что, как я понимаю, не ускорит никаких откликов для клиентов, а наоборот затормозит отклики каждому клиенту.
  • Есть ли преимущество от выполнения задачи в двух потоках на одном ядре?

    @footballer Автор вопроса
    sim3x,
    Я не знаю, какой именно. Абстрактной задачи. Не важно какой. Ну, допустим, каждая подзадача должна прочитать и обработать сложными математическими операциями каждый элемент из огромного массива данных.
  • Почему в var a = new int[1] {5} нет упаковки?

    @footballer Автор вопроса
    eRKa,

    >Чтобы было копирование из стека, надо сделать так
    int a = 42; // положили в стек
    myIntegers[0] = a; // скопировали из стека в выделенное место в куче, упаковки нет, алокаций нет.

    Получается, что в упаковку не входит копирование? Но ведь чаще всего пишут, что именно из-за копирования упаковка медленная? Но тут получается, что копирование из стэка в кучу на самом деле не медленная операции, что противоречит многим статьям в инете. Да и чисто логически, структура может содержать тысячи полей с итн/лонг и т.д, т.е. иметь большой размер, тогда копирование в myInteger[] уж точно должно быть медленным.

    >но не происходит алокации (выделения памяти в куче под объект), а это затратно по вычислениям.

    Если выделение памяти в куче под объект затратно, тогда нужно вообще стараться как можно реже создавать экземпляры типов по ссылке, но про это же никто не говорит.
  • Почему в var a = new int[1] {5} нет упаковки?

    @footballer Автор вопроса
    >. В куче будет выделен неприрывный кусок памяти под значения int и 42 будет хранится в куче как часть массива.

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

    >во второй строке мы не копируем значение из стека

    почему не копируем?

    >Упаковка не просто копирование, это создание оболочки для значения.

    Ок, в случае массива обджектов в куче выделяется память под массив и отдельно под значения массива, в случае с массивом интов в куче выделяется память только под массив, который сам будет содержать значения. Получается, что разница в количестве выделений памяти, но никак не в количестве копирований из стека в кучу (в обоих случаях произойдет одно копирование значения 42 из стека). Но ведь известно, что копирование структур дольше, чем копирование ссылок (т.к. структуры могут быть большого размера, а ссылки маленькие), но т.к. копирование происходит в обоих случаях, то оба массива ( массив интов и массив объектов, заполненный интами) должны быть медленными, но почему-то это не так.

    В общем, я так и не понял причин, почему int[] намного быстрее , чем object[]

    >При упаковке типа значения в куче выделяется экземпляр объекта и выполняется копирование значения в этот новый объект.

    Для int[] в куче тоже должно выполняться копирование значения из стэка в сам массив.
  • Почему в var a = new int[1] {5} нет упаковки?

    @footballer Автор вопроса
    >Упаковка будет происходить со значениями, которые лежат в стеке, а потом копируются в кучу.

    Так в этом случае в первой строке мы тоже сначала выделяем память под инт в стеке и и присваиваем туда значение 42, а во второй строке мы КОПИРУЕМ значение инта в кучу в область памяти, выделенную под массив, почему тогда это не считается медленной упаковкой, раз есть копирование?

    int i = 42;
    myIntegers[0] = 42;
  • Вопрос по статье на Хабре про триггеры - могут ли гарантировать триггеры целостность данных?

    @footballer Автор вопроса
    Denis Popov,
    Но лучше сделать это на сервере, а не средствами СУБД имхо, два запроса при добавлении суммы.

    С точки зрения логики как раз кажется логичнее, чтобы сама SQL-база себя контролировала, а не полагалась на то, что сервер приложения выполнит оба запроса и не забудет про второй. Т.к. я всегда пытаюсь найти логически правильные вещи, то я задумался над тем, что писать триггеры правильно (хотя все пишут, что это замедляет выполнение и т.п., но мне не понятно, как апдейт таблицы totals из триггера может быть медленнее, чем такой же апдейт этой же таблицы из кода приложения, апдейт же в итоге абсолютно одинаковый получается в обоих случаях, разве что в случае с триггером сначала сумму апдейта нужно будет достать из таблицы inserted, но мне кажется, достать запись из этой таблицы не может быть долго). В общем, единственное, что пока меня смущает, так это то, что даже если я в Ms SQL сервере сделаю вспомогательную таблицу totals и повешу триггер AFTER INSERT на таблицу operations, то все-равно сервер приложения может напрямую вызвать изменение данных в таблице totals и нарушить целостность (потому что, насколько я знаю, в MS SQL нельзя скрыть таблицу от внешнего кода, либо я не знаю способ и хотелось бы узнать).
  • Вопрос по статье на Хабре про триггеры - могут ли гарантировать триггеры целостность данных?

    @footballer Автор вопроса
    В статье же написано, для чего.

    Кратко - нужно создать вспомогательную таблицу totals для хранения итоговых сумм на счетах. При добавлении новой суммы к счету (инсерт в таблицу operations), мы должны обновлять итоговую сумму в таблице totals для этого счета. Таблица totals создана для того, чтобы иметь возможность быстро узнать итоговую сумму на счете, не складывая в цикле суммы всех подряд операций на счете из таблицы operations (это медленно).
  • Для чего нужно было придумывать OUTER\CROSS APPLY, если есть JOIN?

    @footballer Автор вопроса
    CROSS APPLY has its obvious usage in allowing a set to depend on another (unlike the JOIN operator)

    Не понял, а разве сджойненные таблицы не означают то же самое, что набор (set, данные) слева зависят от другого набора справа (в той же строке)?

    it behaves like a function that operates over each member of the left set, so, in SQL Server terms it always perform a Loop Join, which almost never is the best way to join sets.

    Снова не понял, а разве join не оперирует точно так же каждой строкой в левом наборе (джойня ее с соответствием в правом наборе)?

    А еще может применить параметризованную функцию к каждой строке и присоединить ее результат.

    А разве при джойне это нельзя сделать (вызвать функцию SomeFunction)?
    SELECT SomeFunction(BB.B1),
         BB.B2,
           A.A1
      FROM [dbo].[A] as A
      cross join (select top 1 B.B1, B.B2 from [dbo].[B] as B where A.BId = B.Id) as BB
  • Обясните по коннекшен пулу и транзакциям в EF и SQL Server - почему так написано по ссылкам?

    @footballer Автор вопроса
    Если я убираю вложенную транзакцию, то второй DbContext выполняется в том же коннекшене, что и первый, т.к. SPID у них равны. В итоге вся транзакция нормально работает. Я правильно понимаю, что это просто совпадение, что 2 разным DbContext выдался один коннекшен, и повторения этого может не быть в следующий раз (потому что на стековерфлоу по ссылке https://stackoverflow.com/questions/21202982/one-t... именно так и написано No, this was a coincidence because the 2nd context reused the connection of the 1st from the connection pool. This is not guaranteed and will break under load.)? Но почему тогда вставка вложенной транзакции меняет SPID?

    Еще я не понял. Профайлер отлавливает запрос коммита после того, как код выходит из блока using, в который завернут transactionScope. Т.е. рассмотрим такой код (он работает, я его протестил):
    using (var transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions {IsolationLevel = IsolationLevel.Snapshot})) 
    {
       using (var dbContext = new DB()) 
       {
         var data1= new Data1();
         dbContext.Table1.Add(data1);
         dbContext.SaveChanges();
       }
       transactionScope.Complete();
       //#1
    }
    //#2

    здесь то, что был коммит, профайлер покажет не на строчке //#1 , а на строчке //#2. Но в этот момент dbContext уже сдиспозился. А коненкшен же привязан именно к dbContext , и именно dbContext умеет слать запросы в БД, а не TransactionScope, так ведь? Как тогда запрос на коммит идет уже после того, как dbContext сдиспозен? Объясните это. И вообще, как я понимал суть работы TransactionScope (у которого нет метода Rollback): во время выхода из скоупа юзинга Dispose у dbContext прочитает из скопа транзакции, был ли вызов коммита, и если мы внутри using (var dbContext = new DB()) вызвали TransactionScope.Commit , то dbContext отправит на sql сервер запрос на коммит, если вызова коммита не было, то dbContext отправит на sql сервер запрос на роллбэк, но все эти запросы, как я понимал, dbContext должен отправлять во время своего диспоза. Но тут получается, что мы вызвали коммит уже после диспоза dbContext. Как тогда запрос на коммит может уходить на sql сервер?
  • В чем смысл запускать на Х-ядерном процессоре более Х потоков?

    @footballer Автор вопроса
    Neyury: насчет моего примера с WCF не получил пока ответ. После вызова host.Open(); в программе запускается сразу 6 потоков. Для чего их столько может быть нужно, если достаточно 1 главного потока и еще 1, который будет слушать сеть? Понятно, что никаких движений мышей и т.п. библиотека WCF не должна отслеживать.
  • В чем смысл запускать на Х-ядерном процессоре более Х потоков?

    @footballer Автор вопроса
    У меня есть прога на .Net WCF. Такой код:
    #1
                var host = new ServiceHost(typeof(AuthenticationService), serviceUri);
                #2
                host.Open();
                #3

    в точке #1 запущен 1 поток, в #2 потоков становится 2, в #3 их становится аж 6. Получается, что WCF запускает аж 6 потоков, чтобы слушать сетевой порт. Для чего он это делает, если достаточно одного потока, слушающего порт, и второго (основного) потока выполнения моей проги? Или он запускает кучу потоков не для слушания сети, а для каких-то других операций (но тогда что это могут быть за операции и есть ли вообще смысл их распараллеливать)?
  • В чем смысл запускать на Х-ядерном процессоре более Х потоков?

    @footballer Автор вопроса
    Именно многопоточность позволяла запускать несколько приложений одновременно на одноядерном процессоре.

    это логичнее многопроцессностью называть. А тут вопрос про то, для чего внутри 1 процесса (1 приложения) много потоков. Потому что даже если внутри всех приложений будет максимум 1 поток, то все-равно ОС позволит организовать многозадачность на одноядерном проце.
  • В чем смысл запускать на Х-ядерном процессоре более Х потоков?

    @footballer Автор вопроса
    То есть, в отдельные потоки выносить имеет смысл только код, который обрабатывает данные, которые он сначала должен получить из источников, которые не управляются нашей операционной системой (и на которые не тратятся ресурсы нашего проца)? В случае с сетью все понятно - это вообще другой комп, и мы не знаем, когда он ответит. В случае с жестким диском - он читает данные данные своей вшитой микропрограммой на своем собственном микропроце и в своем собственном независимом и не принадлежащем ОС "потоке", и ОС никак не управляет тем, как он читает данные (из ОС можно только отправить диску команду "прочитай данные" и просто ждать?)? И если мы отправили команду прочитать данные жесткому диску из единственного потока, то наша прога ничего не будет делать, пока не придут данные от диска. А если мы это делаем в параллельном потоке, то в основном мы может обрабатывать другую операцию (в итоге запускать в разных потоках выгоднее).
    А если предположить, что для чтения данных мы будем юзать хранилище данных, которым управляет ОС. Например, данные лежат в оперативной памяти (т.е. у нас просто в переменной объявлен гигантский массив строк string[]). Я так понимаю, оперативная память должна подойти для этого примера, потому что обращение к данным переменной происходит из нашей же ОС в том же потоке, в котором выполняется код (потому что у опер. памяти, в отличии от диска, нет своего контроллера со своим процем, ну это как я понимаю, хотя я ничего не понимаю в низкоуровневом программировании, поправьте меня тут). Если мы будем обращаться к гигантскому массиву string[] в основном потоке, то операц. система читает данные из массива в потоке нашей же программы. Допустим, все данные у нас читаются и обрабатываются 1 сек, но при этом других потоков нет, и никакие другие операции мы не делаем. Когда данные прочитались и обработались, мы запустим в том же потоке другую операцию, допустим она тоже длится 1 сек. Итого обе операции выполнятся в сумме за 2 сек. А если мы запустим чтение и обработку string[] в отдельном потоке, а вторую операцию в основном потоке, то из-за постоянных переключений потоков чтение данных из string[] будет постоянно прерываться и возобновляться, и аналогично с выполнением операции в основном потоке. В итоге все операции закончатся через те же самые 2 сек, и никакой выгоды от отдельного потока мы не получим?
    То есть, если все кратко резюмировать, что я хотел спросить: если для получения данных мы тратим процессорное время своей ОС (как в случае с опер. памятью), то распараллеливать не имеет смысла (потому что общая производительность данной конфигурации компа всегда константна), а если мы тратим не ресурсы своей ОС, а чужие (как в случае с сетью или с диском), то распараллеливать имеет смысл, чтобы пока внешняя система готовит нам данные, наша система тоже выполняла какую-то работу?
    Кстати, когда поток обращается к сети или диску и начинает ждать данные, то понимает ли ОС, что этому потоку не нужно выделять много проц. времени (потому что пока поток ждет данные, он ничего не будет выполнять, и ресурсы системы пропадут зря). Если система этого не понимает и выделяет одинаковое проц. время основному потоку и потоку, ждущему ответ из сети, то тогда же имеет смысл при создании потока, ждущего данные из сети, параллельно создавать максимальное кол-во потоков, которые бы выполняли полезные расчеты, потому что если есть поток, ждущий сеть, и только 1 полезный поток, то полезный поток будет использовать ресурсы системы только на 50% , а если мы создадим еще 8 полезных потоков, то полезные потоки будут использовать ресурсы системы уже на 90%. В общем, если поток тупо ждет данные из внешнего источника и не выполняет полезной работы, умеет ли система каким-то образом это определять и выделять этому потоку минимум проц. времени, а полезному потоку максимум проц. времени? Или для этого нужно использовать грязный хак "запусти больше полезных потоков - получишь больше полезной работы"?
  • Как правильно разруливать круговые связи между таблицами в БД? И можно ли реализовать такое наследование в Entity Framework?

    @footballer Автор вопроса
    Даю подсказку: пользователю назначается группа по-умолчанию.

    Это можно рассматривать как костыль (нужно создавать строки для групп, которых нет в помине и которые только для прослойки юзера к роли).

    Там есть множественные связи пользователя с группами и ролями. Итоговые роли являются суммой ролей групп и индивидуальных ролей

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

    Вот как лучше такую схему в БД представить? Чтобы без костылей, без избыточности\возможности нарушения целостности , и чтобы еще с EF эта схема работала.