Pull to refresh
45
0
Александр Рулёв @Rulexec

Пользователь

Спасибо за отзыв.


Мне нравится концепция исчезающих фреймворков, возможно, через какое-то время изучу один из них, возможно, Svelte.


Мне не нравится, что фронтенд-фреймворки это какой-то сплошной хайп, за которым сложно уследить (хотя сейчас устаканилось довольно с реактом/vue/angular). А в итоге мы имеем легаси-проекты на первых ангулярах, потому что раньше это было круто.

У меня всё-таки получилось в три раза больше javascript'а. Если не считать папку lib с «моим фреймворком», получается тот же порядок (разницы 20 строк).


recompose-github-ui
recompose-github-ui$ cloc public src
       8 text files.
       8 unique files.                              
       0 files ignored.

-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
CSS                              2             21              0            123
JavaScript                       5             12              0            120
HTML                             1              6             20             17
-------------------------------------------------------------------------------
SUM:                             8             39             20            260
-------------------------------------------------------------------------------

vanilla-github-habr
vanilla-github-habr$ cloc .
      14 text files.
      14 unique files.                              
       1 file ignored.

-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
JavaScript                      12            115              9            358
CSS                              1             25              0             67
HTML                             1             10              0             53
-------------------------------------------------------------------------------
SUM:                            14            150              9            478
-------------------------------------------------------------------------------

Нет, асинхронность может существовать там, где нет никакого event loop'а. Ведь ничто не мешает передать в любой поток коллбэк, который будет вызван, как что-нибудь произошло.


Кооперативная многозадачность решённая через event loop просто порождает асинхронность, а не является ей. Асинхронность — просто абстрактное понятие, описывающее процессы, которые происходят не мгновенно.

Написал «а внутрь неё подаётся получившееся R, либо возбуждается исключение E», но не уточнил, что исключение прямо внутри корутины возникает, ну и примера нет, спасибо.

Тут важно ещё понимать, что «обращение к БД» в основном… не происходит, мы почти всё время просто ждём. Записать/прочитать данные в буффер и отправить его сетевой карте — это относительно быстрая операция, относительно времени, которое проходит между такими операциями. И если у нас времени ожидания достаточно, чтобы ещё повычислять чего-нибудь другого — нам не нужен ещё один поток.

Первое зависит от реализации. Платформа, предоставляющая event loop и асинхронное API действительно может создать сколько угодно других потоков и просто перекидывать данные оттуда в «наш главный». Но по факту новые потоки нужны только если что-то действительно вычисляем, опросить состояние IO (пример с БД) можно и в том же самом. А как там ОС это проворачивает — неизвестно, может у неё отдельный поток тоже для всего IO, я не знаю.


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

Обязательно должны быть те, кто будет ревьювить код, вносимый в настолько важный проект и иметь права на блокирование внесения некоторых коммитов. Иначе шансы на получение бэкдоров/прочих радостей значительно возрастают, чего не хотелось бы.

Я не знаю, как на самом деле устроено ядро и мне вот интересно, почему в ядре настолько много работы и из-за чего её объём может расти? Почему не «закончить» разработку ядра, оставив в нём только совсем стабильные системные абстракции, поддерживать «околоядро», предоставляющее API для взаимодействия модулей, а поддержку оборудования вообще вынести за его пределы? Или оно так и есть? Как оно вообще?
Выглядит так, будто бы оно просто распарсивает функцию и делает из неё генератор.

Почему они с тем же успехом не могли распарсивать функцию и впиливать поддержку await/async? Если это так хочется делать в рантайме, а не транспилировать.

Почему она цилиндрическая?


Что-то на глаз кажется, что можно было сделать параллелепипед, или что-нибудь подобное, что стыкуясь может заполнять весь объём.


А для вентиляции&охлаждения разделять их по слоям, между которыми вставлять какой-нибудь материал, через который свободно проходит воздух и который хорошо проводит тепло.


Или же даже не разделять по слоям, а на самом корпусе аккумулятора сделать канавки для тока воздуха.

Лично по мне, пока ты не объяснил какую-либо технологию кому-нибудь ещё — ты её сам не понимаешь.

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

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

Ну а wait-free — это характеристика lock-free алгоритма, при которой есть гарантии, что, например, для нашего примера очереди, мы не будем крутиться в цикле вечно (т.е. если все подряд кроме нас будут успевать поменять хвост, а нам постоянно будет не везти) — т.е. гарантии того, что есть какое-то конечное время (возможно зависящее от размера структуры данных/количества одновременных её пользователей), за которое мы успешно совершим некую операцию.
Совсем для новичков я ещё когда-то писал Code Hardcorius, но то было довольно давно и мне там уже много чего не нравится (про полиморфизм вообще дичь какая-то несуразная).

Тип X предоставляет A если:


  1. Равен A.
  2. Является произведением типов, один из членов которого предоставляет A.
  3. Является суммой типов, все из членов которой предоставляют A.
  4. Возвращаемое значение функции предоставляет A.

И вот в описании типа A типы, предоставляющие A не могут быть использованы в качестве типа аргумента функций внутри этого типа.


  1. Ограничили типы `T = T → 0`
  2. Ограничили типы `T = (T, AnyOtherTypes) → 0`
  3. Ограничили типы `T = (T + (T, AnyOtherTypes)) → 0`
  4. Ограничили типы `T = (Unit → (T + (T, AnyOtherTypes))) → 0`

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


A = B + C
B = 1 + C
C = 1 + B

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

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


Удалил вообще из содержания пункт про Promises/A+.
Не упоминал про неё, ибо подумал, что она совсем уж микропараллельна, спасибо.

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

В итоге мы получаем сразу две плюшки:

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

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

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

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

Apple, Intel (там ещё горстка других вакансий у них же), NXP, ARM.

И софтварные вакансии тоже иногда появляются, я уверен. И нужно быть готовым к такой, ибо ты не скажешь «ребята, у вас крутая вакансия, подождите, я тут три года попрактикуюсь и сразу к вам».
Не, у нас нет уникальных типов, есть вполне общий Массив n элементов типа T.

И никто не мешает использовать эту n в рантайме.

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

Но, например, если мы просто хотим обойти весь массив, то если мы устроим цикл от 0 до n — нам не потребуется ничего проверять, т.к. будет тривиально получить пруф того, что индекс будет меньше n, ибо нам его генерит цикл и никуда не меняет больше.

Буду дома, может накидаю какой пример кода, как именно оно будет проверяться.
Ещё немного уточню, почему именно так. Когда мы создаём функцию f, внутри неё у нас нет доступа к f и мы не можем сделать рекурсивный вызов. Можно двумя путями дать этот доступ — или передавать её в «конструктор функции», или использовать Y-комбинатор.

Первый путь будет означать, что желая создать функцию f:(A → B), мы будем иметь F = (F → A → B).

Мы только что создали рекурсивный тип. Рекурсивные типы полезны (к примеру, тип списка — рекурсивен: List T = Unit + (T, List T), но не все из них разрешены, т.к. существоние некоторых приводит к возможности получить элемент типа Ложь, в котором по определению нет элементов (т.е. получить противоречие в нашей теории, что уничтожает её целиком).

На примере нашего F = (F → A → B): пусть A = Unit, B = 0 (0 = Ложь). Тогда f p a = p a. Мы корректно определили функцию f, которая валидна по типам, но, к сожалению, приняв значение типа Unit (которое у нас всегда в наличии по определению), мы получим противоречие.

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

С Y-комбинатором те же дела, это просто обобщённая функция, тип которой является запрещённым рекурсивным.

Information

Rating
Does not participate
Location
Брест, Брестская обл., Беларусь
Date of birth
Registered
Activity