Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 与akka一起登录。应用程序设计_Multithreading_Scala_Concurrency_Akka - Fatal编程技术网

Multithreading 与akka一起登录。应用程序设计

Multithreading 与akka一起登录。应用程序设计,multithreading,scala,concurrency,akka,Multithreading,Scala,Concurrency,Akka,假设我有一个基于Futures、在scala.concurrent上的scala应用程序来处理asyn/concurrency(到目前为止没有使用任何参与者) 在许多地方,我使用log4j将内容记录到日志文件中。 由于是I/O,我想我可以通过向LoggingActor发送日志消息来提高性能 大概是这样的: def stuffTodo(arg:String)(implicit ex:ExecutionContext) : Future[Result] = { // important perf

假设我有一个基于
Futures
、在
scala.concurrent
上的scala应用程序来处理asyn/concurrency(到目前为止没有使用任何参与者)

在许多地方,我使用log4j将内容记录到日志文件中。 由于是I/O,我想我可以通过向LoggingActor发送日志消息来提高性能

大概是这样的:

def stuffTodo(arg:String)(implicit ex:ExecutionContext) : Future[Result] = {

 // important performant work
 // .. 
 logAcrot ! LogMessage("message-1")
 // ...
}
其中msg:
case类日志消息(msg:String,隐式ExecutionContext)

然后在
ActorLog

def receive = {
    case LogMessage(msg:String, ex:ExecutionContext) ⇒ {log.info(msg + ex)}
}
我见过其他一些方法,它们基本上是包装
scala.concurent.ExecutionContext
(使用当前线程)并使用-magic(log4j),通过将线程id附加到日志消息来进行日志记录。但最终它会阻止/减慢线程/执行(据我所知),并使应用程序变慢

在这种情况下,对于这个参与者,日志记录保持独立/异步,同时保持顺序


走这条路好吗?分享经验故事?赞成/反对/担忧?在尝试重载之前询问..

这看起来像是过度工程化了

我将使用logback,并实现自定义异步Appender,如果我想这样做的话,那么如果我决定不中断,我就不必更改代码


否则日志库是很好的选择,我可能会尝试调整它以获得更好的性能,并依靠其他人的经验来实现此功能。

Akka已经对日志提供了很好的支持,这在页面上有文档记录。我认为在您的系统中创建一个日志参与者是不必要的,尤其是当这个机制已经存在时

您可能已经使用了异步执行日志记录的
LoggingAdapter
类,它通过将其发布到事件总线来实现这一点。您应该能够在参与者或外部使用相同的机制

看看

记录Mixin

Scala有一个用于actor的mixin,它为actor创建记录器并允许设置MDC。从文件:

import Logging.MDC

final case class Req(work: String, visitorId: Int)

    class MdcActorMixin extends Actor with akka.actor.DiagnosticActorLogging {
        var reqId = 0

        override def mdc(currentMessage: Any): MDC = {
           reqId += 1
           val always = Map("requestId" -> reqId)
           val perMessage = currentMessage match {
              case r: Req => Map("visitorId" -> r.visitorId)
              case _      => Map()
           }
           always ++ perMessage
        }

       def receive: Receive = {
           case r: Req => {
              log.info(s"Starting new request: ${r.work}")
           }
       }
}
在参与者之外登录

Logging.scala
文件中有两个在参与者之外创建LoggingSource的示例:

trait MyType { // as an example
  def name: String
}

implicit val myLogSourceType: LogSource[MyType] = new LogSource[MyType] {
  def genString(a: MyType) = a.name
}

class MyClass extends MyType {
  val log = Logging(eventStream, this) // will use "hallo" as logSource
  def name = "hallo"
}
第二种变体用于包含参与者系统的地址:

如果需要,可以在日志适配器上设置MDC

记录线程和MDC

当日志记录由另一个线程异步执行时,文档还介绍了您在日志记录线程上的观点

由于日志记录是异步完成的,因此 在映射的诊断上下文(MDC)中捕获已执行的日志记录 属性名为sourceThread的。使用Logback时,线程名称为 可与模式布局中的%X{sourceThread}说明符一起使用 配置


跟随你的链接:我做了这个:看起来很有效。但是仍然应该弄清楚如何使布局工作/应用:很好。我已经使用日志文件中的一些示例为其他人更新了答案。
 trait MyType { // as an example
   def name: String
 }

 implicit val myLogSourceType: LogSource[MyType] = new LogSource[MyType] {
   def genString(a: MyType) = a.name
   def genString(a: MyType, s: ActorSystem) = a.name + "," + s
 }

 class MyClass extends MyType {
   val sys = ActorSystem("sys")
   val log = Logging(sys, this) // will use "hallo,akka://sys" as logSource
   def name = "hallo"
  }