IO monad 如何使并发在 Scala 中变得容易?
How IO monad makes concurrency easy to do in Scala?
我看了这个 video 从 6 分 35 秒开始,它提到了这张图:
说 IO Monad 可以轻松处理并发。我对此感到困惑:它是如何工作的?两个for comprehension
如何实现并发(d
和f
的计算)?
不,它不启用并发
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
将由 scala 编译器 转换为 flatMap
和 map
- 给你写
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
}
斯卡拉:
for {
...
yielded_monad <- ```some monad``` // shift function is flatMap/map of the monad
...captured
} yield ...
下次当您看到一种语言功能将后续执行捕获到一个函数中时,您就知道您可以使用该功能实现流控制。
定界延续和call/cc之间的区别在于call/cc捕获程序的整个后续执行,但定界延续有一个范围。
我看了这个 video 从 6 分 35 秒开始,它提到了这张图:
说 IO Monad 可以轻松处理并发。我对此感到困惑:它是如何工作的?两个for comprehension
如何实现并发(d
和f
的计算)?
不,它不启用并发
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
将由 scala 编译器 转换为 - 给你写
flatMap
和map
,你会从参数中得到一个回调函数 - 随时随地调用你得到的函数
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
}
斯卡拉:
for {
...
yielded_monad <- ```some monad``` // shift function is flatMap/map of the monad
...captured
} yield ...
下次当您看到一种语言功能将后续执行捕获到一个函数中时,您就知道您可以使用该功能实现流控制。
定界延续和call/cc之间的区别在于call/cc捕获程序的整个后续执行,但定界延续有一个范围。