[英]Concurrently running Scala FS2 Streams
I am trying to model a system which is a load generator for a website. 我正在尝试对系统进行建模,该系统是网站的负载生成器。 The website has pages which, for now, are Strings.
该网站上的页面目前为字符串。
type Page = String
val pages: Vector[Page] = Stream.eval(Task.delay {
new Random().alphanumeric.take(10).mkString
}).repeat.take(100).runLog.unsafeRun
The website has users which are modeled as starting to browse the website at random times: 该网站的用户被建模为随机开始浏览该网站:
case class User(userName: String)
def newUser: Task[User] = Task.delay {
val random = new Random
val userName = random.alphanumeric.take(5).mkString
val sleepTime = random.nextInt(10000)
println(s"${new Date}: ${Thread.currentThread.getName} Generating user ${userName} after ${sleepTime}ms")
Thread.sleep(sleepTime)
User(userName)
}
Each user transitions from page to page, and that is modeled as: 每个用户都在页面之间转换,其建模方式为:
case class Transition(from: Page, to: Page, thinkTime: Int)
def newTransitions(user: User): Stream[Task, Transition] = {
val init = Transition(pages(0), pages(1), 100)
Stream.iterateEval(init) { t => nextTransition(user)(t) }
}
def nextTransition(user: User)(curr: Transition): Task[Transition] = Task.delay {
val random = new Random
val from: Page = curr.to
val to: Page = pages(random.nextInt(pages.size))
val thinkTime: Int = random.nextInt(10000)
Thread.sleep(thinkTime)
println(s"${new Date}: ${Thread.currentThread.getName} ${user} transitioning from ${from} to ${to} after thinking for ${thinkTime}ms")
Transition(from, to, thinkTime)
}
I am trying to run this simulation, for 4 users starting to browse this website after random intervals, and each user going to three pages at random: 我正在尝试运行此模拟,有4个用户在随机间隔后开始浏览此网站,每个用户随机进入3个页面:
implicit val S = fs2.Strategy.fromFixedDaemonPool(8, threadName = "worker")
val users: Stream[Task, User] = Stream.eval(newUser).repeat
val transitions: Stream[Task, Stream[Task, Transition]] = users.map(newTransitions(_).take(3))
transitions.take(4).runLog.async.unsafeRun.map { _.runLog.async.unsafeRun }
The output looks like: 输出如下:
Sun Oct 16 12:58:04 PDT 2016: worker-1 Generating user 97qkE after 3700ms
Sun Oct 16 12:58:08 PDT 2016: worker-1 Generating user sMIJs after 2074ms
Sun Oct 16 12:58:10 PDT 2016: worker-1 Generating user CpWWf after 1334ms
Sun Oct 16 12:58:11 PDT 2016: worker-1 Generating user xlQmj after 8825ms
Sun Oct 16 12:58:28 PDT 2016: worker-7 User(97qkE) transitioning from sLBbTbXKhO to 7ROMneDkzl after thinking for 8040ms
Sun Oct 16 12:58:34 PDT 2016: worker-7 User(97qkE) transitioning from 7ROMneDkzl to AK66SuDENi after thinking for 6227ms
Sun Oct 16 12:58:41 PDT 2016: worker-6 User(sMIJs) transitioning from sLBbTbXKhO to U2Qu8Th1oH after thinking for 6599ms
Sun Oct 16 12:58:46 PDT 2016: worker-6 User(sMIJs) transitioning from U2Qu8Th1oH to 3bRBWYUeS0 after thinking for 4920ms
Sun Oct 16 12:58:52 PDT 2016: worker-4 User(CpWWf) transitioning from sLBbTbXKhO to ZVwRydhPe9 after thinking for 6395ms
Sun Oct 16 12:58:54 PDT 2016: worker-4 User(CpWWf) transitioning from ZVwRydhPe9 to yHtly5IrMC after thinking for 1963ms
Sun Oct 16 12:58:57 PDT 2016: worker-2 User(xlQmj) transitioning from sLBbTbXKhO to 6jn7TmxW0O after thinking for 2565ms
Sun Oct 16 12:59:05 PDT 2016: worker-2 User(xlQmj) transitioning from 6jn7TmxW0O to FFROVBvpHJ after thinking for 8535ms
ie there is no currency, all the random sleeps happen in strict sequence. 即没有货币,所有随机睡眠都严格按照顺序进行。
How can I change this program such that these different streams (new users starting to browse the website, and transitions made by each user) happen concurrently? 如何更改此程序,以使这些不同的流(新用户开始浏览网站,以及每个用户进行的转换)同时发生?
Here is my complete program: 这是我完整的程序:
import fs2._
import scala.util.Random
import java.util.Date
object Question {
type Page = String
val pages: Vector[Page] = Stream.eval(Task.delay {
new Random().alphanumeric.take(10).mkString
}).repeat.take(100).runLog.unsafeRun
case class User(userName: String)
case class Transition(from: Page, to: Page, thinkTime: Int)
def newUser: Task[User] = Task.delay {
val random = new Random
val userName = random.alphanumeric.take(5).mkString
val sleepTime = random.nextInt(10000)
println(s"${new Date}: ${Thread.currentThread.getName} Generating user ${userName} after ${sleepTime}ms")
Thread.sleep(sleepTime)
User(userName)
}
def nextTransition(user: User)(curr: Transition): Task[Transition] = Task.delay {
val random = new Random
val from: Page = curr.to
val to: Page = pages(random.nextInt(pages.size))
val thinkTime: Int = random.nextInt(10000)
Thread.sleep(thinkTime)
println(s"${new Date}: ${Thread.currentThread.getName} ${user} transitioning from ${from} to ${to} after thinking for ${thinkTime}ms")
Transition(from, to, thinkTime)
}
def newTransitions(user: User): Stream[Task, Transition] = {
val init = Transition(pages(0), pages(1), 100)
Stream.iterateEval(init) { t => nextTransition(user)(t) }
}
def main(args: Array[String]) {
implicit val S = fs2.Strategy.fromFixedDaemonPool(8, threadName = "worker")
val users: Stream[Task, User] = Stream.eval(newUser).repeat
val transitions: Stream[Task, Stream[Task, Transition]] = users.map(newTransitions(_).take(3))
transitions.take(4).runLog.async.unsafeRun.map { _.runLog.async.unsafeRun }
}
}
First off, on your object Question
, looks like there's a typo. 首先,在您的
object Question
,看起来像是有错字。 Remember to switch: 切记切换:
Thread.sleep(sleepTime)
println(s"${new Date}: ${Thread.currentThread.getName} Generating user ${userName} after ${sleepTime}ms")
Next, you'd want to use Task { ... }
instead of Task.delay
since you'd want to run it on a worker thread. 接下来,您要使用
Task { ... }
代替Task.delay
因为您希望在工作线程上运行它。
Finally, last line in your main function should be something like: 最后,主函数的最后一行应类似于:
fs2.concurrent.join(maxOpen = 3)(transitions).run.unsafeRun
Also, I'm guessing that the Thread.sleep
are just placeholders - you wouldn't want to have those in actual code. 另外,我猜想
Thread.sleep
只是占位符-您不希望在实际代码中包含这些占位符。 And the println
's are fine for debugging, but best to move logging as separate stream constructs once finalized. 而且,
println
适用于调试,但是最好在完成后将日志记录作为单独的流构造移动。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.