正确使用scalaz Future进行异步执行

我想我还不完全了解 scalaz Futures的工作原理.我正在尝试将一个项目从scala期货移植到scalaz实现,但问题是scalaz Future的性能较低.最简单的示例是使用Spray在身份验证请求上加载配置文件.

功能本身:

def loadProfile[A: CollectionProvider: JsonFormat](id: String) = future {
  remote.findOne[A]("id" :> id) match {
    case Some(profile) ⇒ \/-(profile)
    case None          ⇒ -\/(ProfileNotFoundRejection(id))
  }
}

scalaz版本只有一个符号,我从scalaz.concurrent调用Future.apply.
现在加载一些html页面的Spray路由:

get {
  path("profile" / "id" ~ Segment) { id ⇒
    onSuccess(loadProfile[User](id)) {
      case \/-(profile) ⇒ complete(html.page(profile))
      case -\/(pnfr)    ⇒ reject(pnfr)
    }
  }
}

与loadProfile一样,scalaz版本仅在方法调用中有所不同:

get {
  path("profile" / "id" ~ Segment) { id ⇒
    ctx => loadProfile[User](id).runAsync {
      case \/-(profile) ⇒ ctx.complete(html.page(profile))
      case -\/(pnfr)    ⇒ ctx.reject(pnfr)
    }
  }
}

但是scala Future版本的请求在(大约)143ms内完成,而scalaz版本在260ms内完成.所以我不太关心这个特殊的请求,但关于异步执行和服务的可伸缩性一般来说,正如我在scalaz中所理解的那样Future我必须手动将执行分叉到一个单独的线程,所以它按顺序执行? scalaz的未来用法是否有任何好的介绍/教程?

解决方法

斯卡拉和斯卡拉斯期货非常不同:

斯卡拉

import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits._

// creating two slow futures:
val f: Future[Unit] = Future { println("f " + Thread.currentThread().getName()); Thread.sleep(10000);  }
val g: Future[Unit] = Future { println("g " + Thread.currentThread().getName()); Thread.sleep(10000);  }

// and after moment asking for success
f onSuccess { case _ => println("f s1 " + Thread.currentThread().getName()) }
g onSuccess { case _ => println("g s1 " + Thread.currentThread().getName()) }
f onSuccess { case _ => println("f s2 " + Thread.currentThread().getName()) }
g onSuccess { case _ => println("g s2 " + Thread.currentThread().getName()) }

我们在创建f和g之后立即获得输出

f ForkJoinPool-1-worker-5
g ForkJoinPool-1-worker-3

约10秒后休息输出

f s1 ForkJoinPool-1-worker-5
g s1 ForkJoinPool-1-worker-5
f s2 ForkJoinPool-1-worker-5
g s2 ForkJoinPool-1-worker-5

Scalaz

import scalaz.concurrent._ // z!
import scala.concurrent.ExecutionContext.Implicits._

// creating two slow futures:
val f: Future[Unit] = Future { println("f " + Thread.currentThread().getName()); Thread.sleep(10000);  }
val g: Future[Unit] = Future { println("g " + Thread.currentThread().getName()); Thread.sleep(10000);  }

创建f和g后,没有任何反应.我们有:

f: scalaz.concurrent.Future[Unit] = Async(<function1>)
g: scalaz.concurrent.Future[Unit] = Async(<function1>)

但在运行它们后,我们看到了不同之处:

f runAsync { _ => println("f s1 " + Thread.currentThread().getName()) }
g runAsync { _ => println("g s1 " + Thread.currentThread().getName()) }
f runAsync { _ => println("f s2 " + Thread.currentThread().getName()) }
g runAsync { _ => println("g s2 " + Thread.currentThread().getName()) }

我们得到结果:

f pool-4-thread-2
g pool-4-thread-1
f pool-4-thread-4
g pool-4-thread-3

f s2 pool-4-thread-4
g s2 pool-4-thread-3
g s1 pool-4-thread-1
f s1 pool-4-thread-2

有两点值得一提:

>期货f和g再次执行.没有价值记忆.
> runAsync回调在与第一次计算相同的线程中执行.这是因为我们没有明确地分叉.

很难说为什么他们在你的例子中表现不同.无论如何,最多的时间应该花在remove.findOne上.您希望使用scala.concurrent.blocking来阻止调用,以帮助ExecutorService不会遇到线程饥饿(在这两种情况下).

相关文章

共收录Twitter的14款开源软件,第1页Twitter的Emoji表情 Tw...
Java和Scala中关于==的区别Java:==比较两个变量本身的值,即...
本篇内容主要讲解“Scala怎么使用”,感兴趣的朋友不妨来看看...
这篇文章主要介绍“Scala是一种什么语言”,在日常操作中,相...
这篇文章主要介绍“Scala Trait怎么使用”,在日常操作中,相...
这篇文章主要介绍“Scala类型检查与模式匹配怎么使用”,在日...