我正在尝试使用此库继续阅读维基百科IRC频道:https://github.com/implydata/wikiticker
我创建了一个自定义的Akka Publisher,它将在我的系统中用作Source
。
以下是我的一些课程:
class IrcPublisher() extends ActorPublisher[String] {
import scala.collection._
var queue: mutable.Queue[String] = mutable.Queue()
override def receive: Actor.Receive = {
case Publish(s) =>
println(s"->MSG, isActive = $isActive, totalDemand = $totalDemand")
queue.enqueue(s)
publishIfNeeded()
case Request(cnt) =>
println("Request: " + cnt)
publishIfNeeded()
case Cancel =>
println("Cancel")
context.stop(self)
case _ =>
println("Hm...")
}
def publishIfNeeded(): Unit = {
while (queue.nonEmpty && isActive && totalDemand > 0) {
println("onNext")
onNext(queue.dequeue())
}
}
}
object IrcPublisher {
case class Publish(data: String)
}
我正在创建所有这些对象:
def createSource(wikipedias: Seq[String]) {
val dataPublisherRef = system.actorOf(Props[IrcPublisher])
val dataPublisher = ActorPublisher[String](dataPublisherRef)
val listener = new MessageListener {
override def process(message: Message) = {
dataPublisherRef ! Publish(Jackson.generate(message.toMap))
}
}
val ticker = new IrcTicker(
"irc.wikimedia.org",
"imply",
wikipedias map (x => s"#$x.wikipedia"),
Seq(listener)
)
ticker.start() // if I comment this...
Thread.currentThread().join() //... and this I get Request(...)
Source.fromPublisher(dataPublisher)
}
所以我面临的问题是这个Source
对象。虽然此实现适用于其他源(例如来自本地文件),但ActorPublisher不会收到Request()
消息。
如果我评论我能看到的两条标记线,我的演员已从我的流程中收到了请求(计数)消息。否则所有消息都将被推送到队列中,但不会在我的流程中(因此我可以看到打印的MSG消息)。
我认为这是多线程/同步的一部分。
答案 0 :(得分:1)
我不熟悉wikiticker来解决你给出的问题。我要问的一个问题是:为什么有必要加入当前的线程?
但是,我认为你使Source
的使用过于复杂。您可以更轻松地使用整个流而不是创建自定义ActorPublisher
。
您可以使用Source.actorRef
将流实现为ActorRef并使用该ActorRef。这允许您利用akka代码对缓冲区进行排队/取消,同时您可以专注于"业务逻辑"。
例如,假设您的整个流只是过滤超过一定长度的行并将其打印到控制台。这可以通过以下方式完成:
def dispatchIRCMessages(actorRef : ActorRef) = {
val ticker =
new IrcTicker("irc.wikimedia.org",
"imply",
wikipedias map (x => s"#$x.wikipedia"),
Seq(new MessageListener {
override def process(message: Message) =
actorRef ! Publish(Jackson.generate(message.toMap))
}))
ticker.start()
Thread.currentThread().join()
}
//these variables control the buffer behavior
val bufferSize = 1024
val overFlowStrategy = akka.stream.OverflowStrategy.dropHead
val minMessageSize = 32
//no need for a custom Publisher/Queue
val streamRef =
Source.actorRef[String](bufferSize, overFlowStrategy)
.via(Flow[String].filter(_.size > minMessageSize))
.to(Sink.foreach[String](println))
.run()
dispatchIRCMessages(streamRef)
dispatchIRCMessages
具有额外的好处,可以与任何ActorRef
一起使用,因此您不需要仅与流/发布商合作。
希望这能解决你的潜在问题......
答案 1 :(得分:1)
我认为主要问题是Thread.currentThread().join()
。此行将“挂起”当前线程,因为此线程正在等待自己死亡。请阅读https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#join-long-。