Comments 40
Спасибо за статью, жду следующих частей. Особенно актуально, если вы опишите асинхронность и остальное в контексте вопросов MS C# Certification, раздел Manage program flow.
Concurrency is not parallelsim.

«In programming, concurrency is the composition of independently executing processes, while parallelism is the simultaneous execution of (possibly related) computations. Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once.»
Да, так и есть. Но ничто не мешает конкурентным процессам выполняться одновременно. Поэтому я всё-таки считаю, что параллелизм это одна из возможных оптимизаций конкурентных подходов, которые существуют вне зависимости от того, есть ли у нас возможность выполнять что-то параллельно на самом деле или нет.

Абсолютно любой многопоточный алгоритм можно переписать в кооперативном стиле, когда код каждого потока будет делать явные yield'ы, чтобы передать управление другому потоку. Или выполнять код в виртуальной машине, считая операции (так, например, в Erlang'е работают их сверхлёгкие процессы).

А когда у нас появляется многопоточность — наши подходы никак не меняются и в основном мы просто создаём столько потоков, сколько у нас логических ядер, и в них выполняем функции, которые берём с какой-нибудь очереди задач. В которую кладём обработчики разных событий, которые возникают от асинхронного I/O.

(а синхронный I/O вряд ли уже кто использует, но его можно реализовать и без параллельного выполнения, достаточно в цикле проверять, есть ли данные, не блокируя, и передавать выполнение другому потоку, если данных нет)

Но, вообще говоря, параллелизм — это один из способов достижения конкурентности.

Не способ. При параллелизме нет конкурентности. Параллелизмом лишь можно ускорить конкурентность. Да и что значит «достижение»? Например, если шедулер решил все треды выполнять на каком-то одном ядре из 8, конкурентность никуда не пропадёт.
Так о том и речь. Распараллеливает шедулер, если он этого делать не будет, конкурентность не исчезнет. А если реализовать конкурентность через параллелизм, то как только все ядра получат по треду, работа выполняться будет, но пользоваться системой будет нельзя. Потому заголовок статьи бессмысленный.

Как это — не исчезнет? Если написать намеренно плохой алгоритм планирования потоков, то конкурентность именно что исчезнет.

А почему исчезнет? Можно с другой стороны подойти. Если параллелизм это один из способов, то вот задача: как выполнить конкурентно 20 потоков на 2 ядрах, используя этот способ?

Какая разница, сколько ядер? Наблюдаемое поведение от их количества не зависит.


Если есть ОС с вытесняющей многозадачностью и адекватным планировщиком, то с точки зрения программы все ее потоки выполняются параллельно.


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

Неплохо еще поднять тему lock-free коллекций ( использование, общая методология написания,… )
Корейцы еще 10 лет назад переплюнули ваши представления о высоконагруженной многопоточности.
Посмотрите на их архитектуры MMORPG серверов. Только в свободном доступе эти исходники не увидеть. Можно только реверс-инженерить.
Так вот ваши асинки, корутины-шмарутины — это детский лепет, на фоне действительно мощных и работающих механизмов.

Такое ощущение, что все придумыватели многопоточных механизмов сами вообще не создавали высоконагруженных серверов, а только как теоретики что-то там выдумывают, и издают об этом книги.
Ну, если Вы эти механизмы изучили, так поделитесь знаниями с общественностью.
Думаю, это будет очень полезно и интересно многим читателям хабра.
Заранее спасибо!
К сожалению, «поделиться» в сфере IT у русских на последнем месте. Я не исключение. Ведь из затраченного времени хочется извлечь прибыль, а в России не выжить без прибыли, это не Норвегия.

В идеале бы создать ITлантиду.
ITлантида — место куда сложно попасть, но если попал, не надо париться о прибыли, люди снабжаются сверхнеобходимого, все работают ради творчества и прогресса, делятся своими наработками с остальным миром, негров правда завозят по пропускам, должен же кто-то чинить унитазы.
Не видел ни одного крутого специалиста, который бы считал невыгодным делиться опытом.
NDA — другое дело, но если вы говорите о реверс-инжиниринге, NDA вряд ли применяется.
Вы и не могли видеть. Крутые специалисты тусят только со своими крутыми специалистами строго в пределах своей компании. А вот джуниоры охотно делятся опытом :))
Есть идея.
Вы не пишите каменты, а мы их, соответственно — не читаем. Для всех профит, и никто не потратил время бесплатно.
Есть идея. Вы не выходите в интернет, и не насилуете свой нежный мозг сложной для вашей психики информацией?
К сожалению, «поделиться» в сфере IT у русских на последнем месте. Я не исключение. Ведь из затраченного времени хочется извлечь прибыль, а в России не выжить без прибыли, это не Норвегия

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

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

А сейчас догнал, что они действительно lock-free, но не прям совсем так, чтобы не было блокировок — просто они не используются для блоков кода в принципе, алгоритм используя только атомарные переменные в цикле пытается применить некую операцию до тех пор, пока у него не получится (для добавления в очередь, например, это может быть просто CAS хвоста в цикле, если успеем заменить его до того, как успел кто-то другой — то и славно).

Ну а wait-free — это характеристика lock-free алгоритма, при которой есть гарантии, что, например, для нашего примера очереди, мы не будем крутиться в цикле вечно (т.е. если все подряд кроме нас будут успевать поменять хвост, а нам постоянно будет не везти) — т.е. гарантии того, что есть какое-то конечное время (возможно зависящее от размера структуры данных/количества одновременных её пользователей), за которое мы успешно совершим некую операцию.
Ничего там особо умного нет, корутины, запиленные на Си-чётамувас.
Классный пост:
  • Посмотрите на архитектуры, которые закрыты;
  • Асинки и корутины-шмарутины говно, ведь у Корее есть принципиальное новые средства синхронизации (на самом деле не новые, ведь они уже 10 лет назад все придумали);
  • Мировой computer science говно, то ли дело Корея!
  • Ну и, конечно, только в Корее есть MMORPG, которые справляются с большими нагрузками :)


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

+ векторизация (SIMD)
Не упоминал про неё, ибо подумал, что она совсем уж микропараллельна, спасибо.

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

Можете подробнее разъяснить нарушение данных, если вести запись в невыровненный адрес.

Поток А: записать по адресу 01 значение АА
Поток В: записать по адресу 01 значение ВВ
Возможна такая ситуация: (атомарна запись 2 значений)
А: записывает А по адресу 01 (00: ХАХХ)
переключаем на поток В
В: делает полную запись (00: ХВВХ)
А: записывает вторую половину значения (00: ХВАХ)
Получается по адресу 01 значение ВА

Вот в этом заголовке есть ошибка: "Promises/A+ — мгновенно стартующие монады с PubSub'ом".


Во-первых, не любая поддержка событий является PubSub'ом. Конкретно тот механизм, который предусмотрен в Promises/A+ — точно не PubSub. PubSub подразумевает подписку на сообщения на основе данных или метаданных — но никак не прямое указание источника событий для обработки.


Во-вторых, почему все прошлые заголовки относились к надъязыковым понятиям — а тут вдруг используется нечто javascript-специфичное? В том же C# есть аналог этих самых обещаний.


В-третьих, почему вдруг обещания будут рассматриваться после async/await — в то время как async/await на обещаниях и построены?

  1. Да, некорректно, просто не нашёл другого короткого понятия. Тут я имею в виду, что в случае с данной реализацией промисов всё сделано так, что можно сразу нескольким обработчикам дожидаться результата промиса. И метод .then там это примерно «если промис ещё резолвится, сделай addThenListener(callback), а если зарезолвен, то сделай callback(data)». Да, совсем не PubSub, чистые события.
  2. Промисы реализует кто как хочет, они действительно везде есть, но я хочу показать один из примеров, как их реализовывать не стоит (хотя некоторые плюсы всё же есть, о них тоже расскажу).
  3. Я расскажу о том, как работают обещания перед тем, как будет про async/await, всё будет ок.


Удалил вообще из содержания пункт про Promises/A+.
сохранение идентификатора потока, кто захватил блокировку, чтобы никто кроме захватившего потока, не мог сделать Unlock, и если мы сделали Lock второй раз — он не зациклился, такая реализация это называется «мьютексом». А если вместо boolean'а у нас беззнаковое число, а Lock ждёт числа больше нуля, уменьшая его на единицу, получается «семафор», позволяющий работать некоторому заданному числу блоков одновременно, но не более.

Да, мьютекс в ядре реализован с помощью спин-блокировок, но если мьютекс уже захвачен, при попытке захватить его другой поток просто заснет, т.е. будет «пассивная» блокировка. Поэтому мне не совсем понятно, почему о мьютексах и семафорах написано в разделе Spinlock. Возможно, во фразе «поток не зацикливается» и имеется в виду «засыпание», но мне кажется, что для кого-то это не очевидно.

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

В асинхронности ещё можно поговорить о ново-(старо-)модном Functional Reactive Programming. Более требовательный к дизайну, зато на разработке не будет боли с callback hell.

P.S. Таки конкурентность != парелеллизм. Это всё таки о целях, а не о реализации.
Такое же как и остальное перечисленное — это ещё один паттерн. В отличие от параллельного программирования, асинхронное требует всего один механизм на уровне системных вызовов — select, poll, epoll или ещё что. Все перечисленные неявно его используют, разница только на верхнем уровне.
Отвечая на сам вопрос: FRP — это stateless способ выбрать ответ на пришедший запрос в реальном времени.

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


А вот про stateless способ выбрать ответ на входящий запрос я почему-то слышу впервые… Не могли бы вы пояснить эту мысль?

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

В чистом (в смысле функционального программирования) FRP состояние передаётся в качестве ещё одного аргумента вместе с нашим горизонтальным временем. На выходе соответственно получаем ответ и изменённый state. Профит в том, что прошлое не задерживается в графе, что сильно упрощает последующую отладку.
А где-то в глубине — обычный event-loop, дёргающий FRP граф, когда срабатывает poll. Я бы это не называл «способ организации кода», всё-таки это про проектирование, а не про написание кода.

Если речь идет об "измененном state" — это по определению не stateless подход, пусть даже код 100500 раз чистый, функциональный и простой в отладке.

Only those users with full accounts are able to leave comments. Log in, please.