Как монада IO делает параллелизм простым в Scala?
Я смотрю это видео и начинается в 6min35s, он упомянул этот график:
говоря, что IO Monad облегчает параллелизм. Я запутался в этом: как это работает? Как сделать два for comprehension
включить параллелизм (вычисление d
а также f
)?
1 ответ
Нет, это не включает параллелизм
for
Понимание только поможет вам опустить несколько скобок и отступов.
Код, который вы указали, переведите на [flat]map
строго эквивалентно:
async.boundedQueue[Stuff](100).flatMap{ a =>
val d = computeB(a).flatMap{
b => computeD(b).map{ result =>
result
}
}
val f = computeC(a).flatMap{ c =>
computeE(c).flatMap{ e =>
computeF(e).map{ result =>
result
}
}
}
d.merge(f).map(g => g)
}
Видите, это только поможет вам опустить несколько скобок и отступов (шутка)
Параллельность скрыта в flatMap
а также map
Как только вы понимаете, как for
переводится на flatMap
а также map
, вы можете реализовать свой параллелизм внутри них.
Как map
принимает функцию в качестве аргумента, это не значит, что функция выполняется во время выполнения map
Функция, вы можете перенести функцию на другой поток или запустить его позже. Вот как реализован параллелизм.
принимать Promise
а также Future
как пример:
val future: Future = ```some promise```
val r: Future = for (v <- future) yield doSomething(v)
// or
val r: Future = future.map(v => doSomething(v))
r.wait
Функция doSomething
не выполняется во время выполнения Future.map
вместо этого она вызывается, когда promise
совершает.
Заключение
Как реализовать параллелизм с помощью for
синтаксис suger:
for
превратится вflatMap
а такжеmap
компилятором scala- Написать тебе
flatMap
а такжеmap
где вы получите функцию обратного вызова из аргумента - Вызывайте функцию, которую вы получили, когда и где угодно
дальнейшее чтение
Функция управления потоком во многих языках имеет одно и то же свойство, они как продолжение с разделителями shift/reset
где они фиксируют следующее выполнение до области видимости в функцию.
JavaScript:
async function() {
...
val yielded = await new Promise((resolve) => shift(resolve))
// resolve will captured execution of following statements upto end of the function.
...captured
}
Haskell:
do {
...
yielded_monad <- ```some monad``` -- shift function is >>= of the monad
...captured
}
Scala:
for {
...
yielded_monad <- ```some monad``` // shift function is flatMap/map of the monad
...captured
} yield ...
в следующий раз, когда вы увидите языковую функцию, которая фиксирует последующее выполнение в функции, вы знаете, что можете реализовать управление потоком с помощью этой функции.
Разница между продолжением с разделителями и call / cc заключается в том, что call / cc захватывает все последующее выполнение программы, но продолжение с разделителями имеет область действия.