ermouth: (Default)
[personal profile] ermouth

Наткнулся только что в кейноте по новым предложениям для javascript.

Снимок экрана 2015-04-22 в 3.10.50

Это значит, что мы можем расшаривать данные между workers, со всеми плюшками. То-есть теперь в js есть threads, ну, или совсем скоро будут.

Многопоточность в C++ понимании в JS-мире нужна очень редко (да и в остальных мирах, по-хорошему, тоже) – но зато когда она нужна, без неё туго.

Это, например, вещание потоковых стримов из воркера нескольким (торрент)-слушателям через WebRTC или аналогичные применения. Это разделяемые мемкэши в веб-серверах. Это навороченные игры.

Игры от меня далеко, а вот два других применения – очень даже мне близки.

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

---

Вот хорошо бы ещё пионэры JS-комьюнити смотрели и в сторону Erlang, а не только Emscripten/C++.

Date: 2015-04-22 01:58 am (UTC)
From: [identity profile] archaicos.livejournal.com
Того гляди и арифметику с указателями сделают. :)

Date: 2015-04-22 05:56 am (UTC)
From: [identity profile] archaicos.livejournal.com
FUUUU...!!!

Date: 2015-04-22 04:27 am (UTC)
From: [identity profile] morfizm.livejournal.com
Немного офтопик, но прекрасное про javascript, вдруг ты не видел:
https://www.destroyallsoftware.com/talks/wat

Я сегодня смотрел :)

Date: 2015-04-22 05:24 pm (UTC)
From: [identity profile] ermouth.livejournal.com
Посмотрел. В самом деле всё ещё хуже:

eval('{{{{5}}}}') → 5; eval('{}+[]') → 0; x = {}+[] → "[object Object]"; eval('{}+{}') → NaN; #javascript #magic

— ermouth (@ermouth) October 12, 2014

Date: 2015-04-24 04:50 pm (UTC)
From: [identity profile] morfizm.livejournal.com
Параллельные потоки это ещё и более простая парадигма программирования, скажем, для фоновых задач разного обновления, чем event-driven кусочками по таймеру, и эффективнее работать будет. Люди не умеют корректно кодить state machines, это не естественно для них.

Date: 2015-04-24 05:19 pm (UTC)
From: [identity profile] ermouth.livejournal.com
Для них? Любопытно, к какому виду ты себя относишь )

Насчёт «неестественно» – у меня ровно противоположное мнение. Я как раз считаю, что конечные автоматы удобнее и понятнее, чем трэды, если есть подходящий инструмент. Обычно это удачный DSL (регэкспы, $.my опять же) или заточенный под конечные автоматы язык программирования (Erlang).

Хотя пословицу «всяк кулик своё болото хвалит» никто не отменял.

Главная то беда в том, что конечные автоматы на практике не всегда удобны, а иногда и просто неприменимы из-за возникающего оверхэда. Вот для этих редких хадач трэды и нужны.

Date: 2015-04-24 05:59 pm (UTC)
From: [identity profile] morfizm.livejournal.com
Для них - для людей. Отношу себя к людям, конечно.

Мне не верится, что автоматы могут быть легче для восприятия, чем императивный код. Покажи хоть один нетривиальный пример.

Например, покажи мне, как твоё волшебноё болото сгенерирует конечный автомат для вот такого куска:

while B1:
  S1
  for i in 1..N:
    S2
    for j in 1..M:
      if B2: S3
      if B3:
        while B4: S4
        while B5: for k in 1..P: S5
        if B6: S6
      else:
        S7
        while B7: S8
        S9


Я хочу исполнять это в фоновом режиме, выполняя лишь 1 строку со стейтментом (S1, S2... S9) по каждому вызову таймера (мне специально задержки не нужны, но я буду возвращаться после каждого statement'а, чтобы не блокировать UX).

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

Date: 2015-04-24 06:07 pm (UTC)
From: [identity profile] ermouth.livejournal.com
Изволь, вот общий подход превращения трэдов в конечный автомат, тут хорошо и коротко.

http://programmers.stackexchange.com/a/110206

Не такое уж и уродство кста получается, если S[] – это список функций.

Date: 2015-04-24 06:12 pm (UTC)
From: [identity profile] morfizm.livejournal.com
Я знаю общий подход, и так же хорошо понимаю, что полученный результат будет (для среднего девелопера, в т.ч. для меня) в разы более сложным для чтения, чем приведённый кусок. Если ты по-другому это воспринимаешь, ну, типа, круто :) Но необычно.

Date: 2015-04-24 06:20 pm (UTC)
From: [identity profile] morfizm.livejournal.com
Кстати, в реальной жизни S[] это не просто функции, а функции с параметрами, тянущимися из локального скопа (типа, i, j, k, и, возможно, какие-то результаты предыдущих вызовов). Энкапсулирование состояния одно из значительных усложнений. Хотя в данном примере сам факт вложенных циклов, а также последовательность нескольких действий под if-ом это уже усложнение. Императивный код читается как структура, конечный автомат читается как кусочки, которые надо как-то увязать в голове.

Единственный более-менее нормальный выход это использование yield (пишешь императивный код, а компилятор/интерпретатор всё делает за тебя).

Date: 2015-04-24 06:30 pm (UTC)
From: [identity profile] ermouth.livejournal.com
В js пока официально нет yield, только в ES6 будет, так что только чисто функциональный подход, без читерства.

Энкапсулирование состояний элементарно делается замыканиями (это, правда, ой недёшево – замыкания то подороже стеков обходятся).

С появлением promise как общего соглашения картинка кста существенно упростилась и код с длинными асинхронными цепочками/графами переходов состояний стал приемлемо (и даже легко) читаться.

Date: 2015-04-24 06:53 pm (UTC)
From: [identity profile] morfizm.livejournal.com
Замыкания плохи не тем, что они могут быть неэффективны (в C++, кстати, они достаточно эффективно реализованы), они плохи тем, что их трудно читать. Куски фрагментированы и нужно в голове соединять узлы графа. Код, над которым нужно *думать*, причём думать не только, чтобы понять, что он делает, а чтобы понять, как он организован - его структуру, что в каком порядке вызывается, это сложный код. Сложный код это плохой код - он не масштабируется на сотню девелоперов, половину времени работающих с кодом, который они видят впервые в жизни, и им нужно качественно разобраться за несколько секунд беглого чтения.

Date: 2015-04-24 07:06 pm (UTC)
From: [identity profile] ermouth.livejournal.com
Ой, да брось. Четыре вложенных итератора труднее понять, чем четыре цикла?

Такое плохо читается, по-твоему? Это несколько псевдокод, но сейчас вот так дела обстоят.

Number.range(0,I)
.every(function(i){
   S[0](i)
  .then(function(S0result){
    return Promise.all(
      Number.range(0,K)
      .map(function(k){
         return S[1](i,k);
      })
   );
  })
  .then(function(){ /* .... */})
})

Date: 2015-04-25 11:11 pm (UTC)
From: [identity profile] morfizm.livejournal.com
Хм. Твой вариант очень хорошо читается.

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

Наверное, нужен пример чуть больше, чем тривиальный, чтобы это показать.

Date: 2015-04-26 11:28 am (UTC)
From: [identity profile] ermouth.livejournal.com
Код, который сразу писали в таком стиле и на правильном языке, как правило всё-же хорошо читается.

Код, который писали, натягивая за уши функциональный стиль, да на неприспособленном языке – читается как говно. Два прекрасных примера – php и java. Там да, код в таком стиле – просто кровавое месиво.

Насчёт коллбэков: коллбэки как конструкции – вообще обычно зло. Сравни:

var f = function (arg, callback) { ...; callback (result)};
f(123, function(res){...});

против
 var f = Promisify(function(arg) { return result});
var cb = Promisify(function (res){...}), 
    cb1 = Promisify(function (res){...})
f(123)
.then(cb)
.then(cb1)
.fail( function(err){...});


Во втором случае аж два «коллбэка» плюс обработка ошибок decoupled от самих функций.

Промисы проще читаются, в них проще обрабатывать ошибки и обычно понятно, что куда передаётся. Они, правда, довольно дорогие.

Не понял насчёт создания лямбд не инлайном – лямбда же просто стрелка, как её можно не инлайном? Её ж именовать придётся.

Profile

ermouth: (Default)
ermouth

November 2021

S M T W T F S
 123456
78910111213
14151617181920
21 222324252627
282930    

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jun. 11th, 2025 01:46 am
Powered by Dreamwidth Studios