LINUX.ORG.RU

Смешной код

 , , ,


1

2

Решил сравнить подходы к написанию кода в различных ЯП

actorScript Карла Хьюитта

(↓Future  slowProcedure∎[10, 20])+↓Future  slowProcedure∎[30, 40]
наш любимый JS


new Promise(function(resolve, reject){
  setTimeout(function(){
  try{
    resolve(slowProcedure(10, 20))
  }catch(e){
    reject(e)
  }})
 })
 .catch(function(e){console.log("first: " + e)})
 .then(function(x){
   return new Promise(function(resolve, reject){
     try{
       resolve(x + slowProcedure(30, 40))
     }catch(e){
       reject(e)
     }
   })
  })
 .catch(function(e){console.log("second: " + e)})
 .then(function(x){console.log(x)})


Это разве не смешно?

Что-то скриптовый язык для показывания alert'ов многовато о себе возомнил.

anonymous ()

resolve(slowProcedure(10, 20))

Напоминаю: Javascript так не работает. Да и вообще, ничего так не работает. Тебе как минимум нужно yield'ить эту slowProcedure. Или оборачивать в Worker/setTimeout/whatever.

В таком виде твой код работает синхронно и ты можешь с тем же успехом написать

function() {
  try {
    return slowProcedure(10, 20) + slowProcedure(30,40);
  }
  catch(e) {
    //do whatever you want. wrap each slowProcedure call in catch if you wish.
  }
}
Каким образом, по-твоему, slowProcedure будет работать параллельно хоть чему-то? Это тебе не golang и к javascript нет изкоробочного gevent-подобного костыля.

x3al ★★★★★ ()
Последнее исправление: x3al (всего исправлений: 1)
Ответ на: комментарий от x3al

работает синхронно

Щито?


slowProcedure=function(x, y){return x+y}

new Promise(function(resolve, reject){
  try{
   resolve(slowProcedure(10, 20))
  }catch(e){
   reject(e)
  }
 })
 .catch(function(e){console.log("first: " + e)})
 .then(function(x){
   return new Promise(function(resolve, reject){
     try{
       resolve(x + slowProcedure(30, 40))
     }catch(e){
       reject(e)
     }
   })
  })
 .catch(function(e){console.log("second: " + e)})
 .then(function(x){console.log(x)})

console.log("foo")

//>>>> foo
//>>>> 100

javaQest ()
import {parallel} from 'async'

parallel(
  {
    x: (cb) => slowProcedure(10, 20, cb),
    y: (cb) => slowProcedure(30, 40, cb)
  },
  (err, res) => console.log(err ? `Error: ${err}` : `Result: ${res.x + res.y}`)
);
static_lab ★★★★★ ()
Последнее исправление: static_lab (всего исправлений: 2)
Ответ на: комментарий от javaQest

Ок, моя ошибка, недочитал спеку Promises/A+. Действительно, в JS оно резольвится асинхронно.

x3al ★★★★★ ()
Ответ на: комментарий от x3al

Ок, моя ошибка, недочитал спеку Promises/A+. Действительно, в JS оно резольвится асинхронно.

Да нифига, он просто засунул синхронный код в промис. Ничего там асинхронно работать не будет.

holuiitipun ()

Это не смешно, это индусский говнокод

Goury ★★★★★ ()

Это язык для поклонников витчхауса?

Midael ★★★★★ ()
Ответ на: комментарий от holuiitipun

Прямо перед .then возвращение контроля в eventloop, что-то будет работать асинхронно. Хотя я хз, зачем: с одним тредом от такой асинхронности нифига не легче, а другие он не прикрутил.

x3al ★★★★★ ()
Ответ на: комментарий от javaQest
slowProcedure=function(x, y){
  console.log('First run *before* log(foo)');
  return x+y;
}

new Promise(function(resolve, reject){
  try{
    console.log('Not really async')
   resolve(slowProcedure(10, 20))
  }catch(e){
   reject(e)
  }
 })
 .catch(function(e){console.log("first: " + e)})
 .then(function(x){
   return new Promise(function(resolve, reject){
     try{
       resolve(x + slowProcedure(30, 40))
     }catch(e){
       reject(e)
     }
   })
  })
 .catch(function(e){console.log("second: " + e)})
 .then(function(x){console.log(x)})

console.log("foo")

Первый запуск slowProcedure — до console.log(«foo»), что очевидно.

x3al ★★★★★ ()
Последнее исправление: x3al (всего исправлений: 1)
Ответ на: комментарий от x3al

Прямо перед .then возвращение контроля в eventloop, что-то будет работать асинхронно.

А, я про то как slowProcedure вызывается.

holuiitipun ()
Ответ на: комментарий от holuiitipun

во, а ты у нас, оказывается, анскильная лалка. Что такое асинхронность, вообще без понятия. А я и думаю, че это ты там иммутабельные структуры все ищешь, а оно вон как.

javaQest ()
Ответ на: комментарий от javaQest

во, а ты у нас, оказывается, анскильная лалка. Что такое асинхронность, вообще без понятия. А я и думаю, че это ты там иммутабельные структуры все ищешь, а оно вон как.

Ну и где там у тебя асинхронность, если slowProcedure блокирующая?

Уточню, если твоя slowProcedure будет выполняться 5 секунд (факториал большой считать или что-то такое), то всё это время ничего другое не будет исполняться.

holuiitipun ()
Последнее исправление: holuiitipun (всего исправлений: 1)
Ответ на: комментарий от x3al

Прямо перед .then возвращение контроля в eventloop

Тогда уж не перед then а перед catch, в данном случае,но тут не правильно говорить о возвращении, потому что мы никуда фактически не уходим. Мы сконфигурировали объект, который выполнится интерпретатором асинхронно, позже.

javaQest ()
Ответ на: комментарий от holuiitipun

Ну чо тебе сказать, Вань, я даже не знаю. Иди дальше факториалы считай. Врешь наверное, что 5 лет программистом работал без трудовой?

javaQest ()
Ответ на: комментарий от javaQest

Ну чо тебе сказать, Вань, я даже не знаю. Иди дальше факториалы считай. Врешь наверное, что 5 лет программистом работал без трудовой?

Ну придумай свою долгую операцию, просто так возвращающую результат.

holuiitipun ()
Ответ на: комментарий от holuiitipun

то всё это время ничего другое не будет исполняться.

В однопоточной среде, всегда что-нибудь одно выполняется, Вань. Но это асинхронности не отменяет

javaQest ()
Ответ на: комментарий от javaQest

В однопоточной среде, всегда что-нибудь одно выполняется, Вань. Но это асинхронности не отменяет

Есть блокирующие и не блокирующие операции. Заворачивать в промисы есть смысл только вторые.

holuiitipun ()
Ответ на: комментарий от holuiitipun

longOperation=function(x){
 console.time("whatever")
 while(x--){}
 console.timeEnd("whatever")
 return x
}


new Promise(function(resolve, reject){
  setTimeout(function(){
    resolve(1000000000)
 })
})
 .then(function(n){
  return new Promise(function(resolve, reject){
     resolve(longOperation(n))
  })
})
 .then(function(data){console.log(data)})

console.log("foo")




//>>>> foo
//>>>> whatever: 2920ms
//>>>> -1
javaQest ()
Ответ на: комментарий от javaQest

В однопоточной среде, всегда что-нибудь одно выполняется, Вань. Но это асинхронности не отменяет

Когда ты асинхронно выполняешь IO-операцию, во время ожидания результата управление у eventloop'а и он запускает всё остальное. Никаких фризов.

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

Это проблема всех green-тредов, без настоящего треда ты ничерта с этим не сделаешь. Разве что твоя медленная блокирующая операция будет сама периодически возвращать контроль в эвентлуп, но я хз, как это вообще будет выглядеть конкретно в js.

Ещё Javascript ужасно неудобен тем, что невозможно в одной функции асинхронно запустить функцию и получить её результат. Можно лишь асинхронно запустить и передать результат в коллбэк (в том числе тот, что в .then). И без yield/await это нифига не изменится.

Да, я в курсе, что генераторы и, соответственно, yield в некоторых браузерах есть, но его нельзя полифиллить (тот же Promise — запросто), поэтому применение ограничено. Если только транслировать код в безгенераторную версию.

x3al ★★★★★ ()
Ответ на: комментарий от x3al

Ещё Javascript ужасно неудобен тем, что невозможно в одной функции асинхронно запустить функцию и получить её результат.

Дак ведь это в принципе невозможно. На момент выхода из ф-ции, так называемый коллбэк еще не запущен.

С другой стороны, какая разница, что ты будешь считать возвратом, и где ловить.

Но синтаксис неудобен в целом, с этим я согласен. И подход ущербен. Я поэтому и привел этот код на actorScript для сравнения.

javaQest ()
Ответ на: комментарий от x3al

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

помоему, это очень просто выглядит. Надо просто пробросить код через setTimeout

javaQest ()
Ответ на: комментарий от javaQest

Дак ведь это в принципе невозможно.

await и yield делают именно это. Оба варианта на время уступают управление, в обоих случаях после выполнения результат и управление возвращаются в эту же функцию.

Естественно, справа от await/yield должна стоять асинхронная функция, из обычной они асинхронную не сделают.

x3al ★★★★★ ()
Ответ на: комментарий от javaQest

Не-а, не выйдет. setTimeout поставит функцию в очередь, но оно не запустится, пока slowProcedure не завершится. setTimeout значит «когда будешь свободен, но не раньше timeout», не «строго через timeout», он не отберёт управление.

part 5 тут — как это выглядело в питоне, я думаю, что с некоторыми оговорками в js это можно повторить с генераторами. Минус: писать eventloop руками (и да, всё, что не в этом велосипедном eventloop, запускаться не будет).

Можно скрестить с fiber'ами к node.js, впрочем. Ничего более умного без настоящих тредов не сделать.

x3al ★★★★★ ()
Ответ на: комментарий от x3al

Хотя я брежу и путаю yield с yield from. Нет, всё-таки это не так просто.

x3al ★★★★★ ()
Ответ на: комментарий от x3al

делают именно это

Я чо то не совсем понял. Ты же говорил о возврате значения. А эта хрень, вроде, возвращает генератор.

javaQest ()
Ответ на: комментарий от javaQest

Если посмотреть на генератор сбоку, то он похож на процесс. Подробности — в презентации по ссылке чуть выше, начиная с части 5 и дальше. Осторожно, упорото, не пользуйтесь в продакшн и ждите await.

Чуть позже питонисты сделали yield from, где эксепшном StopIteration передают результат асинхронно в вызывающую функцию. И это вроде как портировали в питон2, где только обычный yield, поэтому должно быть реализуемо и в js.

x3al ★★★★★ ()
Последнее исправление: x3al (всего исправлений: 1)
Ответ на: комментарий от x3al

setTimeout поставит функцию в очередь, но оно не запустится,

Я имею в виду, вместо блокирующего кода, например цикла,

fu1=function(x){
  while(--x) {console.log(x)}
}

пробросить через таймаут

fu2=function(x){
  if(--x){console.log(x); setTimeout(fu2(x))}
}
или setInterval использовать.

В этом смысле

javaQest ()
Ответ на: комментарий от javaQest

Сойдёшь с ума с коллбэками и попытками всё это синхронизировать и определить, что после чего должно быть запущено. Даже если пользовать Promise.

Всё, что в setTimeout, выполнится только после того, как вызывающая функция завершится.

x3al ★★★★★ ()
Последнее исправление: x3al (всего исправлений: 1)
Ответ на: комментарий от javaQest

[code]fu2=function(x){

if(--x){console.log(x); setTimeout(fu2(x))} }

fu2=function(x){
  if(--x){console.log(x); setTimeout(function(){fu2(x)})}
}

//fixed

javaQest ()
Ответ на: комментарий от x3al

Всё, что в setTimeout, выполнится только после того, как вызывающая функция завершится.

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

javaQest ()
Ответ на: комментарий от x3al

я об этом

fu2=function(x){
  if(--x){console.log(x); setTimeout(function(){fu2(x)})}
}

fu2(5)
fu2(5)


4
4
3
3
2
2
1
1

javaQest ()
Ответ на: комментарий от javaQest

Тебе в setTimeout нужно будет закинуть не только тяжёлый цикл, но и всё после него. В случае с yield можно оставить цикл циклом без всяких setTimeout и оставить всё после него в той же функции.

https://pypi.python.org/pypi/trollius/ — пример того, как на одном yield построили асинхронность. В оригинале был yield from, которым пользовались точно так же, как await, но тут — пруф того, что синтаксис для yield from нафиг не нужен, достаточно обычного yield.

http://jlongster.com/A-Closer-Look-at-Generators-Without-Promises тут это уже реализовано на javascript. Никаких setTimeout, yield честно возвращает результат из асинхронной функции прямо в вызывающую его. Можно пользоваться yield в тяжёлом цикле, и цикл останется циклом.

x3al ★★★★★ ()
Ответ на: комментарий от holuiitipun

+1. slowProcedure должна иметь callback, иначе все это профанация

dib2 ★★★★★ ()
Ответ на: комментарий от dib2

Ога, а коллбек должен иметь свой коллбек, а тот свой, и так до бесконечности.

javaQest ()
Ответ на: комментарий от javaQest

Вот так твой код в ОП может выглядеть, если slowProcedure возвращает результат в node-style коллбэке

var suspend = require('suspend');

suspend(function*(resume) {
  first = yield slowProcedure(10, 20, resume);
  if(first[0]) throw first[0];
  second = yield slowProcedure(30, 40, resume);
  if(second[0]) throw second[0];
  console.log(first[1] + second[1]);
})();
x3al ★★★★★ ()
Последнее исправление: x3al (всего исправлений: 1)
var suspend = require('suspend'),
  resume = suspend.resume;

suspend.run(function*() {
  console.log((yield slowProcedure(10, 20, resume())) + (yield slowProcedure(30, 40, resume())));
});
x3al ★★★★★ ()
Последнее исправление: x3al (всего исправлений: 1)
auto t1 = async( bind( slowProcedure, 10, 20 ) );
auto t2 = async( bind( slowProcedure, 30, 40 ) );
    
cout << t1.get() + t2.get() << '\n';
anonymous ()
Ответ на: комментарий от anonymous

Хотя я протупил, bind не нужен:

auto t1 = async( slowProcedure, 10, 20 );
auto t2 = async( slowProcedure, 30, 40 );
    
cout << t1.get() + t2.get() << '\n';
anonymous ()
import Control.Concurrent.Async

main = (+) <$> Concurrently (slowProcedure 10 20) <*> Concurrently (slowProcedure 30 40)
KblCb ★★★★★ ()
func main() {
	ch := make(chan int)
	go func() {
		ch <- slowProcedure(10, 20)
	}()
	x := <-ch
	go func() {
		ch <- x + slowProcedure(30, 40)
	}()
	fmt.Println(<-ch)
}
Deleted ()
Ответ на: комментарий от Deleted

Что-то ты перемудрил.

func main() {
	ch := make(chan int)
	go func() { ch <- slowProcedure(10, 20) }()
	go func() { ch <- slowProcedure(30, 40) }()
	fmt.Println(<-ch + <-ch)
}
korvin_ ★★★★★ ()
Ответ на: комментарий от korvin_

Тут время третьей горутины, проведенное в блокировке, должно быть больше.

Впрочем, неважно.

Deleted ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.