如何与演员一起使用Tinkerpop

时间:2014-01-02 15:15:41

标签: 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.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线程

以下是我想要实现的示例项目:https://github.com/D-Roch/tinkerpop-play

2 个答案:

答案 0 :(得分:7)

问题

问题是,Tinkerpop工作线程本地。因此,您的更改仅提交给当前线程。在创建Scala期货时,您让环境选择,在哪个线程中执行未来。并且环境不是更好,所以它选择了错误的线程。

Akka期货的问题类似。

未来在哪个线程中运行?

创建未来时,您将使用两个参数创建它:

  1. 应执行的块
  2. 应执行块的Execution Context
  3. 第二个参数通常作为隐式参数给出。但您可以覆盖默认值。

    解决方案

    在创建处理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线程中运行的未来。或者你可以创建一个特殊的actor来封装所有tinkerpop交互(并使用特殊的tinkerpop exection上下文运行它们)。

    文献

答案 1 :(得分:4)

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

try graphChanges finally { ... }

它看起来很好,但我也可以看到graphChanges在这里创造了一个未来。所以......

  • graphChanges启动未来,立即返回
  • try块完成并执行finally
  • 在此之前,之后或可能并行的某个时刻,但几乎可以肯定在另一个主题上,执行Future

我的建议是将异步逻辑移到test中,这样就可以确保正确的线程关联,并确保所有调用都被正确标记为blocking。像这样:

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
}