Совсем скоро, 29-30 ноября в Санкт-Петербурге и 06-07 декабря — в Москве мы запустим шестой семинар по .NET. На этот раз — по теме многопоточки и конкурентности. Мы уже писали об этом пару раз на Хабре, но сегодня есть отдельный повод для этого: на семинаре настоящий эксклюзив. Будет описана работа гибридного примитива синхронизации: Monitor. Да, всем привычная вещица достойна отдельного доклада. Ведь он в своей работе учитывает и частоту процессора и количество ядер, учитывает lock convoy/starvation и вообще, очень сложен.


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



Небольшой сценарий с семинара


Самое важное, что исходит от операционной системы — это планирование потоков. Ведь они могут работать как в параллели друг с другом (когда в данный момент исполняются на разных ядрах), так и что чаще (если речь идёт об одних и тех же потоках) — последовательно. Ведь ОС даёт не так много времени на исполнение — каждому, после чего отдает время другим. Второе — для этого отрезка — кванта — может быть выделено разное количество времени. Например, в зависимости от того, какой версией ОС мы пользуемся: серверной или пользовательской, является ли поток UI потоком процесса с текущим активным окном. Третье — есть приоритеты и понятие "вытесняющая многозадачность", когда ваш поток, только получив заветный квант может его потерять, т.к. образовался другой поток с более высоким приоритетом. Получается, что наше приложение сильно зависит от того, в каком окружении оно работает. Например, какой-нибудь расчётный сервис лучше всего будет себя чувствовать на серверном варианте ОС (либо с соответствующими настройками производительности), когда на машине нет вообще никаких других сервисов: кванты будут длинными, квантового времени будет предоставлено много.


Но тут встаёт другой вопрос: если наш поток на такой конфигурации устанавливает блокировку уровня ядра (например, Semaphore(1) ), второй поток дойдя до установки блокировки у себя в эту блокировку встаёт, то стоять он в серверной ОС будет намного дольше, чем стоял бы в пользовательской. Почему? Да потому что квант времени серверной в 6 раз длиннее, чем у клиентской и этому потоку придется сначала подождать, когда первый поток дойдёт до места снятия блокировки, а потом — когда ему выдадут новый квант.


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


CLRium 6


Эти три абзаца — это сжатые 5% от 4-го доклада. А он уже богат на информацию, которой можно воспользоваться на всех уровнях: от работы с примитивами синхронизации до работы с высокоуровневыми библиотеками. А программа у нас такая:


  1. Мы посмотрим на типы процессов. Ведь их много, а пользуемся мы от силы двумя из них: это обычные и ModernApp;
  2. Три доклада подряд — это потоки уровня операционной системы: планирование на одноядерных, многоядерных системах и NUMA системах. Везде правила — разные и это надо учитывать в своей работе;
  3. Разбор работы примитивов синхронизации на уровне квантового времени. Говорить о lock/Mutex/Semaphore вы все научились на собеседованиях. Нет никакого смысла повторяться, а потому мы вооружимся временными графиками и посмотрим, как распределяются кванты между процессорами на всех примитивах синхронизации: Kernel-Space, User-Space и гибридных.
  4. Настоящий эксклюзив семинара: строение примитива Monitor. То, что lock(){} раскрывается в try { } finally { } вы и без меня знали, а вот во что раскрывается Monitor.Enter, Monitor.Leave, Monitor.TryEnter — это тема для отдельного, плотного, полного ада доклада. Поверьте, внутри у него всё очень и очень круто. Это — гибридный примитив синхронизации, который построен избегать Starvation, излишних уходов в блокировку и lock convoy.
  5. Целых три плотных доклада по lock-free и wait-free в том числе на примере разведовательных дронов и ПВО, пытающейся сбить эти дроны. И эти доклады настолько понравились HighLoad++, что их позвали на HighLoad++ в Москве 07-08 ноября.
  6. Ряд докладов по PLINQ и Async-Await. Всё тоже максимально подробно. Не по вешкам: этого добра хватает в Интернете. Каждая технология будет рассказана "изнутри": как это принято на CLRium.
  7. И закроют семинар два доклада по библиотеке lock-free коллекций от Microsoft и Intrinsics (векторные инструкции для параллелизации на уровне процессора).

Немного статистики


Мы — крупнейший семинар страны и в общем не являемся конференцией только потому, что нам нравится наш формат. Вы не выбираете среди докладов, на которые вы не пойдёте. Вы идёте на все. При этом вы заранее понимаете, что все темы семинара вам интересны, т.к. тема едина. На CLRium 6 будет поставлен очередной рекорд: в обоих городах будет присутствовать 700 человек. Около 700 человек прокачают свои навыки в параллелизации и работой с конкурентностью. И пойдут на собеседования. Приходите и вы к нам :).

Комментарии (8)


  1. kdmitrii
    31.10.2019 00:17
    +1

    "многопроцессорных (NUMA) системах"
    NUMA это Non Uniform Memory Access. Определяет грубо говоря правила по которым процессор общается с памятью (основная суть этого общения в том что разные ядра имеют разную скорость доступа к разным блоками памяти). Никакого отношения к многопроцессорности не имеет. NUMA блоки есть на любом современном процессоре с достаточным количеством ядер (обычно больше 8).


    1. Nova_Logic
      31.10.2019 03:53
      +1

      Как это не имеет? Ядра имеют одинаковую скорость доступа к памяти, но могут иметь разную скорость доступа к данным в памяти, каналы которых принадлежат другой NUMA node.
      Условно:
      Дано:
      Два процессора( или 2
      Чиплета) по 8 ядер.
      Сценарий 1:
      Доступ к памяти, привязанной к каналам памяти у CPU0 — скорость доступа почти одинаковая
      Сценарий 2:
      Ядру с CPU0 потребовались данные в памяти, каналы которой привязаны к CPU1- и вот тут-то возникает дополнительный временной лаг на необходимость через интерконнет обратиться к памяти, которой владеет CPU1. И даже если речь о чиплетах внутри какого-нибудь Amd epyc, там неизбежно каналы памяти будут первично принадлежать разным чиплетам, что потребует чиплету 0 через infinity fabric обратиться к чиплету 1 для получения данных, лаг может и меньше чем между интерконнектом между сокетами, но все-равно он не нулевой


      1. Nova_Logic
        31.10.2019 07:39
        +1

        Для минусящего в ASCII:
        image
        И ответьте себе на вопрос одинаковая ли скорость доступа к памяти у ядер?
        На мой взгляд именно у ядер одинаковая. А далее возникает вопрос а в памяти какого процессора находятся данные.
        NUMA делают не исходя из кол-ва ядер, а исходя из физической архитектуры процессора. И если она предполагает архитектуру как у условных threadripper,epyc, многопроцессорных систем — то начинают включать NUMA Блоки, чтобы планировщик не планировал по возможности потоки одного процесса на ядра из разных NUMA node, чтобы не оказалось что для приложения, обрабатывающего данные, находящиеся на планке в канале A, поток был запланирован на ядра CPU1, не имеющего прямого соединения с каналом A


        1. mayorovp
          31.10.2019 10:13

          Всё это замечательно, но всё равно не делает NUMA и многопроцессорность синонимами.


          1. sidristij Автор
            31.10.2019 10:25

            NUMA скорее вытекает из многоядерности и многопроцессорности, увеличивая параллелизм.


    1. sidristij Автор
      31.10.2019 08:38

      Согласен, написал не совсем корректно, подправил.


  1. zed220
    31.10.2019 23:47

    Надеюсь, будет запись. Прошлый доклад был чудовищно интересным.


    1. sidristij Автор
      01.11.2019 08:56

      Запись будет, но не будет 100% во всеобщем онлайн доступе: только тем, кто купил билеты. А во всеобщем будет доступна только небольшая часть.