了解Scala中的未来

时间:2014-10-10 08:34:38

标签: scala asynchronous playframework future reactivemongo

我在Scala中编写了一个Play 2.3.2应用程序。 我使用reactivemongo驱动程序访问mongodb数据库。 我已经编写了该查询db以获取数据库中最常用的标记。 此方法是Action.async,并按以下方式实现:

def max = Action.async { request =>

          var max: Int = 0
          var tagFound: Tag = null
          //obtain all the tags in the db.
          val futureTags: Future[List[Tag]] = Tags.all.toList
          futureTags map{ (tags: List[Tag]) => 
            tags map { (tag: Tag) => 
              //create the tag String 
              val tagName = tag.category  + ":" + tag.attr 
              //search in the db the documents where tags.tag == tag.
              val futureRequests : Future[List[recommendationsystem.models.Request]]= Requests.find(Json.obj("tags.tag" -> tagName)).toList
              futureRequests map { (requests: List[recommendationsystem.models.Request]) =>
                //get the numbers of documents matching the tag
                val number: Int= requests.size
                if(number > max) {
                  max = number
                  tagFound = tag
                }
                println(max)
              }
            }   

         val jsonObject = if(max > 0) Json.obj("tag" -> tagFound, "occurencies" -> max) else Json.obj("tag" -> "NoOne", "occurencies" -> 0)
         Ok(jsonObject)
         }


      }

但这种方法的行为不确定,有什么不对?

我无法理解
val jsonObject = if(max > 0) Json.obj("tag" -> tagFound, "occurencies" -> max) else Json.obj("tag" -> "NoOne", "occurencies" -> 0)
             Ok(jsonObject)
             }

执行异步,不要等待tags map语句完成。

2 个答案:

答案 0 :(得分:1)

我发现您的代码存在一些问题:

  1. 不要用户,你不知道什么时候会更新,因此不确定。       事实上,根本不要使用变种
  2. 你使用map作为foreach,即你不从map返回任何值,如果你未从以后返回任何值,则显式使用foreach
  3. 以展平Future [Future [T]]使用flatMap,
  4. 将List [Future [T]]转换为Future [List [T]]使用Future.sequence
  5. 这是一段重写的代码,我没有编译它,但你可以知道它应该如何工作:

    def max = Action.async { request =>
        Tags.all.toList.flatMap { case tags =>
          val xs = tags map { case tag =>
            val tagName = tag.category  + ":" + tag.attr 
            Requests.find(Json.obj("tags.tag" -> tagName)).toList.map (requests => (tag, requests.size) )
          }
          val f = Future.sequence(xs)
          f.map { case ys =>
             val res = ys.foldLeft(Option.empty[(Tag, Int)]) { 
                case (Some((maxTag, maxOcc)), (tag, occ)) if occ > maxOcc => Some(tag, occ)
                case (s@Some(_), _) => s
                case (None, (tag, occ)) => Some(tag, occ)
             }
             val jsonObject = res.map { case (tag, maxOcc) =>
               Json.obj("tag" -> tagFound, "occurencies" -> maxOcc)
             } getOrElse {
                 Json.obj("tag" -> "NoOne", "occurencies" -> 0)
             }
             Ok(jsonObject)
          }
    
        }
    }
    

答案 1 :(得分:0)

Future.map会返回另一个Future - 它不会立即运行。致电f.map(...)后,f可能尚未完成。

如果您要在Future完成之前阻止,请使用Future.get(这样您就可以f.map(...).get,但在这种情况下您也可以执行f.get并执行此操作对该值的计算 - 当然这不是非阻塞的)。如果您想将多个异步计算链接在一起,可以使用flatMapsequence,并且在@ vitalii的答案中应尽量避免使用var s。

-Ywarn-value-discard编译器标志可以在您丢弃值时向您发出警告,这通常表示该程序存在问题。