Как построение вычислений для больших задач сравнивается с одновременным выполнением нескольких шагов?

У меня есть следующие две части кода, написанные на Scala/Monix:

def f1(input) =
  for {
    a <- task1(input)
    b <- task2(a)
    c <- task3(b)
  } yield (c).runSyncUnsafe

а также

def f2(input) = {
  val a = task1(input).runSyncUnsafe
  val b = task2(a).runSyncUnsafe
  task3(b).runSyncUnsafe
}

Я думаю, что версия f1 лучше, поскольку она полностью асинхронна и не блокирует потоки, и я предполагаю, что, если выполняется много задач, первая должна работать лучше в многопоточности.

Я знаю, что должен написать тест для сравнения двух реализаций, но это потребовало бы большого количества рефакторинга унаследованного кода. Кроме того, профилирование двух версий не так просто в нашей конкретной ситуации, поэтому я сначала спрашиваю здесь, в надежде получить ответ от кого-то с большим опытом работы с Scala/Monix:

Как они должны сравниваться с точки зрения производительности при большой нагрузке? Это реальная проблема или это не проблема?

1 ответ

Как правило, лучше оставаться асинхронным как можно дольше. Чтобы ты мог написать f1 как это:

def f1(input) =
  for {
    a <- task1(input)
    b <- task2(a)
    c <- task3(b)
  } yield c

После этого вызывающий абонент может решить, следует ли ему позвонить. runSyncUnsafe или асинхронный вызов (runAsync, runOnComplete) или же flatMap это с другой задачей. Это удаляет Unsafe позвоните из своего кода и оставьте его вызывающему абоненту, чтобы решить, будет ли он в безопасности или нет.

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

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