我正在创建一个运行在单词列表中的服务,并且每个单词都会检查数据库中是否存在相关操作(执行)。
我正在尝试使用Futures同时执行此操作,但我不确定我是否使用了最佳方式。
```
class CommandDiscoveryService (commandsDAO: CommandsDAO, text: String) {
val words = text.split("\\s+")
var results = new ListBuffer[Option[Execution]]()
// Temporarily handle with concurrent searchs on the database
// TODO Load all commands to memory and check the list ?? memcache or some other cache service
if (words.size <= 6) {
Logger.debug("Searching for executions with text " + text )
findExecution()
}
def findExecution() = {
val lb = new ListBuffer[Future[Seq[Execution]]]()
for (word <- words) {
lb += commandsDAO.findExecutionByName(word)
}
lb.foreach(Await.result(_, 1 seconds))
import scala.concurrent.ExecutionContext.Implicits.global // FIXME LATER
val res = lb.map {
ftr => ftr.map{
res => {
if (res.size > 0 ) {
Logger.debug("RES SIZE:" + res.size)
res.map{ ex => results += Some(ex) }
}
}
}
}
}
def getExecution(): Option[Execution] = {
if (results.size > 1 ) {
Logger.debug("ERROR_TOMANYEXECS: Found more than one execution " + results.head)
results.foreach{
execs => Logger.debug("ERROR_TOMANYEXECS: " + execs)
}
None
} else {
if (results.size == 0 ) {
Logger.debug("NOTHING FOUND IN RES")
None
} else {
Logger.debug("FOUND RES " + results.head)
results.head
}
}
}
}
```
当我调用getExecution时,我需要已经获得了搜索完成的值。我不确定是否对这个结果变量进行锁定将是一个解决方案对未来的等待[Seq [执行]]已经没有建议。
PS:我正在使用playframework 2.6.x和Slick来运行它。
答案 0 :(得分:2)
您的results
ListBuffer
仅填充了Some[Execution]
,绝不会使用None
,因此使用Option
没有任何意义。我建议使用不可变集合并重新定义findExecution
方法以返回Future[List[Execution]]
:
val words = text.split("\\s+").toList
def findExecution: Future[List[Execution]] = {
val executions = words.map(commandsDAO.findExecutionByName(_)) // List[Future[Seq[Execution]]]
val filtered = executions.map(_.filter(_.nonEmpty)) // List[Future[Seq[Execution]]
val flattened = Future.sequence(filtered).map(_.flatten) // Future[List[Execution]]
flattened
}
findExecution
现在返回所有单词或名称的所有Future
中的Execution
个单词,除了没有任何Execution
s的单词。< / p>
当我调用getExecution时,我需要已经获得了搜索完成的值
更好的方法是让getExecution
同时返回Future
:
def getExecution: Future[Option[Exception]] = {
val executions = findExecution // Future[List[Execution]]
executions.map { e =>
if (e.size > 1) {
// ...
None
} else if (e.isEmpty) {
// ...
None
} else { // e.size is one
// ...
Some(e.head)
}
}
}
上述方法避免了阻塞Await
调用,并且适合异步Play和Slick API。