点击次数超过总请求数
Hits more than total requests
所以我开始学习Scala和Akka actor,Akka-Http。我尝试使用 Akka Http 实现一个简单的点击计数器,它计算本地主机页面上的每次点击。我使用 wrk 工具 运行 10 个线程和 100 个连接,之后计数和请求总数不匹配(在 wrk 上看到)。
这是我的代码:
object WebServer3 {
var number: Int = 0
final case class Inc()
class ActorClass extends Actor with ActorLogging {
def receive = {
case Inc => number = number + 1
}
}
def main(args: Array[String]) {
implicit val system = ActorSystem("my-system")
implicit val materializer = ActorMaterializer()
implicit val executionContext = system.dispatcher
val actor1 = system.actorOf(Props[ActorClass], "SimpleActor")
val route =
path("Counter") {
get {
actor1 ! Inc
complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, s"<h1>You visited $number times</h1>"))
}
}
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
StdIn.readLine() // let it run until user presses return
bindingFuture
.flatMap(_.unbind()) // trigger unbinding from the port
.onComplete(_ => system.terminate()) // and shutdown when done
}
}
请原谅我的 immature/amateurish 编码技巧。我仍在学习,我知道这与并发性有关。但我还找不到解决办法。请帮忙。
编辑#1:我也试过 AtomicInteger。那没有帮助。
编辑#2:我也尝试了使用 ask 和 await 的完整 akka-http 方式。这也没有帮助。
您的代码几乎没有问题。
您正在定义一个案例 class final case class Inc()
但您正在发送一个伴随对象 actor1 ! Inc
。但是,您仍然匹配伴随对象 case Inc =>
并且您的代码有效。但不应该这样做。
其他问题,我们正在 actor 边界之外存储、修改和检索 var number: Int = 0
。我认为这就是你计算错误的原因。 Actor 必须只改变内部状态。
我通过引入 ask pattern 修改了您的代码,因此可以从 actor 中检索值。
import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{ContentTypes, HttpEntity}
import akka.http.scaladsl.server.Directives._
import akka.pattern.ask
import akka.stream.ActorMaterializer
import akka.util.Timeout
import scala.concurrent.duration._
import scala.io.StdIn
object WebServer3 {
final case object IncAndGet //not a case class anymore
class ActorClass extends Actor with ActorLogging {
private var number: Int = 0 //inner state must be private and not accessible from outside of an actor
def receive = {
case IncAndGet =>
number += 1
context.sender() ! number // send current value back to sender
}
}
def main(args: Array[String]) {
implicit val system = ActorSystem("my-system")
implicit val materializer = ActorMaterializer()
implicit val executionContext = system.dispatcher
implicit val timeout: Timeout = 2.seconds
val actor1 = system.actorOf(Props[ActorClass], "SimpleActor")
val route =
path("counter") {
get {
onComplete((actor1 ? IncAndGet).mapTo[Int]) { number =>
complete(
HttpEntity(ContentTypes.`text/html(UTF-8)`,
s"<h1>You visited $number times</h1>"))
}
}
}
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
StdIn.readLine() // let it run until user presses return
val _ = bindingFuture
.flatMap(_.unbind()) // trigger unbinding from the port
}
}
所以我开始学习Scala和Akka actor,Akka-Http。我尝试使用 Akka Http 实现一个简单的点击计数器,它计算本地主机页面上的每次点击。我使用 wrk 工具 运行 10 个线程和 100 个连接,之后计数和请求总数不匹配(在 wrk 上看到)。
这是我的代码:
object WebServer3 {
var number: Int = 0
final case class Inc()
class ActorClass extends Actor with ActorLogging {
def receive = {
case Inc => number = number + 1
}
}
def main(args: Array[String]) {
implicit val system = ActorSystem("my-system")
implicit val materializer = ActorMaterializer()
implicit val executionContext = system.dispatcher
val actor1 = system.actorOf(Props[ActorClass], "SimpleActor")
val route =
path("Counter") {
get {
actor1 ! Inc
complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, s"<h1>You visited $number times</h1>"))
}
}
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
StdIn.readLine() // let it run until user presses return
bindingFuture
.flatMap(_.unbind()) // trigger unbinding from the port
.onComplete(_ => system.terminate()) // and shutdown when done
}
}
请原谅我的 immature/amateurish 编码技巧。我仍在学习,我知道这与并发性有关。但我还找不到解决办法。请帮忙。
编辑#1:我也试过 AtomicInteger。那没有帮助。 编辑#2:我也尝试了使用 ask 和 await 的完整 akka-http 方式。这也没有帮助。
您的代码几乎没有问题。
您正在定义一个案例 class final case class Inc()
但您正在发送一个伴随对象 actor1 ! Inc
。但是,您仍然匹配伴随对象 case Inc =>
并且您的代码有效。但不应该这样做。
其他问题,我们正在 actor 边界之外存储、修改和检索 var number: Int = 0
。我认为这就是你计算错误的原因。 Actor 必须只改变内部状态。
我通过引入 ask pattern 修改了您的代码,因此可以从 actor 中检索值。
import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{ContentTypes, HttpEntity}
import akka.http.scaladsl.server.Directives._
import akka.pattern.ask
import akka.stream.ActorMaterializer
import akka.util.Timeout
import scala.concurrent.duration._
import scala.io.StdIn
object WebServer3 {
final case object IncAndGet //not a case class anymore
class ActorClass extends Actor with ActorLogging {
private var number: Int = 0 //inner state must be private and not accessible from outside of an actor
def receive = {
case IncAndGet =>
number += 1
context.sender() ! number // send current value back to sender
}
}
def main(args: Array[String]) {
implicit val system = ActorSystem("my-system")
implicit val materializer = ActorMaterializer()
implicit val executionContext = system.dispatcher
implicit val timeout: Timeout = 2.seconds
val actor1 = system.actorOf(Props[ActorClass], "SimpleActor")
val route =
path("counter") {
get {
onComplete((actor1 ? IncAndGet).mapTo[Int]) { number =>
complete(
HttpEntity(ContentTypes.`text/html(UTF-8)`,
s"<h1>You visited $number times</h1>"))
}
}
}
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
StdIn.readLine() // let it run until user presses return
val _ = bindingFuture
.flatMap(_.unbind()) // trigger unbinding from the port
}
}