Как монада 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:

  1. for превратится в flatMap а также map компилятором scala
  2. Написать тебе flatMap а также mapгде вы получите функцию обратного вызова из аргумента
  3. Вызывайте функцию, которую вы получили, когда и где угодно

дальнейшее чтение

Функция управления потоком во многих языках имеет одно и то же свойство, они как продолжение с разделителями 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 захватывает все последующее выполнение программы, но продолжение с разделителями имеет область действия.

Другие вопросы по тегам