Scala 如何与演员一起使用Tinkerpop

Scala 如何与演员一起使用Tinkerpop,scala,playframework-2.0,akka,thread-local,tinkerpop,Scala,Playframework 2.0,Akka,Thread Local,Tinkerpop,我想知道我是否可以在Akka Futures中使用tinkerpop,到目前为止,当我将更改提交到图形时,它们不会被持久化。 我知道tinkerpop是一个线程本地库,这意味着我需要在将来再次设置线程ODatabaseRecordThreadLocal.INSTANCE.set(thread) 我尝试了以下方法,但没有成功: def test[T](graphChanges: => T): T = { val thread = ODatabaseRecordThreadLocal.

我想知道我是否可以在Akka Futures中使用tinkerpop,到目前为止,当我将更改提交到图形时,它们不会被持久化。 我知道tinkerpop是一个线程本地库,这意味着我需要在将来再次设置线程
ODatabaseRecordThreadLocal.INSTANCE.set(thread)

我尝试了以下方法,但没有成功:

def test[T](graphChanges: => T): T = {
    val thread = ODatabaseRecordThreadLocal.INSTANCE.get
    try graphChanges finally {
      ODatabaseRecordThreadLocal.INSTANCE.set(thread)
      GraphPool.get("partitioned").commit
    }
}

// collect tinkerpop frames
test {
  future {
  // add changes to my tinkerpop frames
  }
}
我希望每个play.mvc.Http.Context有一个Tinkerpop线程


下面是一个我想要实现的示例项目:

这看起来不像是Tinkerpop特有的,它看起来像是使用Futures时出现的常见错误。只要考虑一下这个片段:

try graphChanges finally { ... }
它本身看起来不错,但我也可以看到
graphChanges
正在创造一个未来。所以

  • graphChanges
    启动未来,立即返回
  • try
    块完成,最后执行
  • 在此之前或之后的某个时间点,或者并行执行,但几乎可以肯定的是在另一个线程上执行
    Future
我的建议是将异步逻辑移到
test
中,这样您就可以确保线程关联正确,并确保所有调用都被正确标记为
阻塞
。像这样:

def test[T](graphChanges: => T): Future[T] = future {
  blocking {
    val tlocal = ODatabaseRecordThreadLocal.INSTANCE
    val dbrecord = tlocal.get

    try graphChanges finally {
      tlocal.set(dbrecord)
      GraphPool.get("partitioned").commit
    }
  }
}

// collect tinkerpop frames
test {
  // add changes to my tinkerpop frames
}
问题 问题是,Tinkerpop在线程本地工作。因此,您的更改只提交到当前线程。在创建Scala futures时,您可以让环境选择未来将在哪个线程中执行。而且环境也不太清楚,所以它选择了错误的线程

阿克卡期货的问题也类似

将来运行的线程是哪个? 创建未来时,您将使用两个参数创建它:

  • 应该执行的块
  • 应该执行该块的
  • 第二个参数通常作为隐式参数给出。但您可以覆盖默认值

    解决方案 在使用Tinkerpop创建期货时,请使用在同一线程中运行每个块的执行上下文

    例如:

    import scala.concurrent.ExecutionContext
    import java.util.concurrent.Executors
    
    implicit val ec=ExecutionContext.fromExecutorService(Executors.newSingleThreadExecutor)
    
    future { 
        println(Thread.currentThread); 
        future {
            println(Thread.currentThread)
        }  
    }
    
    这段代码在控制台上打印两次相同的线程id(使用Java 7和Scala 2.10.2测试)

    注意:使用这样一个小的线程池很容易导致死锁或饥饿。只在你的Tinkerpop交互中使用它

    您可以提供一个特殊的方法tinkerpopFuture,该方法将一个块作为参数并返回一个将在tinkerpop线程中运行的future。或者您可以创建一个特殊的actor来封装所有tinkerpop交互(并在特殊tinkerpop执行上下文中运行它们)

    文学类
    • 您可以看到一些创建执行上下文的示例代码
    • 文件

    感谢您的输入,这很有意义,但我真的不知道如何继续,我是否应该在以后重写exec上下文:您使用scala.concurrent.future方法,该方法接受类型为“ExecutionContext”的隐式第二个参数。在您的情况下,它将从import ExecutionContext.Implicits.global获取默认ExecutionContext。您可以通过提供“implicit val TINKEROPCTX:ExecutionContext=…”来覆盖此设置使用单线程执行上下文。有关隐式参数的更多详细信息,请参阅“谢谢”,我了解隐式变量如何工作,但我应该传递什么来替代ExecutionContext?您只需使用一个ExecutionContext,它将在一个线程中运行所有内容。您可以使用java.util.concurrent.ExecutionService(例如,ExecutionContext.fromExecutorService(ExecutorService.newSingleThreadExecutor)。我必须尝试正确的语法,然后在上面的答案中添加一个示例。令人印象深刻,感谢您的解释,我不希望答案这么简单;-)我做了一些测试,得到了很好的结果,但并不完美:正如您看到的第456行,我得到了一个失败的插入,但可能只是orientdb?