2014-04-18 13 views
9

Đây là vấn đề, tôi có một thư viện có phương thức chặn trả về Thử [T]. Nhưng vì nó là một ngăn chặn, tôi muốn làm cho nó không bị chặn bằng cách sử dụng Future [T]. Trong khối tương lai, tôi cũng muốn tính toán điều gì đó phụ thuộc vào giá trị trả về của phương thức chặn gốc.Cách tốt nhất để bọc chặn Hãy thử [T] trong tương lai [T] trong Scala là gì?

Nhưng nếu tôi sử dụng một cái gì đó như dưới đây, thì nonBlocking của tôi sẽ trả về Tương lai [Thử [T]] ít thuyết phục hơn vì Future [T] có thể đại diện cho Failure [U], tôi thà tuyên truyền ngoại lệ cho tương lai [T] là tự.

def blockMethod(x: Int): Try[Int] = Try { 
    // Some long operation to get an Int from network or IO 
    throw new Exception("Network Exception") } 
} 

def nonBlocking(x: Int): Future[Try[Int]] = future { 
    blockMethod(x).map(_ * 2) 
} 

Dưới đây là những gì tôi cố gắng, tôi chỉ sử dụng .get phương pháp trong future {} khối, nhưng tôi không chắc chắn nếu điều này là cách tốt nhất để làm điều đó.

def blockMethod(x: Int): Try[Int] = Try { 
    // Some long operation to get an Int from network or IO 
    throw new Exception("Network Exception") } 
} 

def nonBlocking(x: Int): Future[Int] = future { 
    blockMethod(x).get * 2 
} 

Đây có phải là cách chính xác để làm điều đó không? Hoặc có một cách scala thành ngữ hơn để chuyển đổi t Thử [T] thành Tương lai [T]?

Trả lời

14

Dưới đây là một ví dụ mà không chặn, lưu ý rằng bạn có thể muốn sử dụng bối cảnh thực hiện của riêng bạn và không bối cảnh toàn cầu scala của:

import scala.util._ 
import scala.concurrent._ 
import scala.concurrent.duration._ 
import ExecutionContext.Implicits.global 

object Main extends App { 

    def blockMethod(x: Int): Try[Int] = Try { 
    // Some long operation to get an Int from network or IO 
    Thread.sleep(10000) 
    100 
    } 

    def tryToFuture[A](t: => Try[A]): Future[A] = { 
    future { 
     t 
    }.flatMap { 
     case Success(s) => Future.successful(s) 
     case Failure(fail) => Future.failed(fail) 
    } 
    } 

    // Initiate long operation 
    val f = tryToFuture(blockMethod(1)) 

    println("Waiting... 10 seconds to complete") 

    // Should return before 20 seconds... 
    val res = Await.result(f, 20 seconds) 

    println(res) // prints 100 
} 
+0

Nếu bạn biết mình đang chặn, bạn có nên quấn mã trong 'chặn' không? –

+0

Phương thức 'fromTry' có hữu ích cho việc này không? http://www.scala-lang.org/api/current/#scala.concurrent.Future$ – stefanobaghino

+0

Tự sửa lại nhận xét trước của tôi: 'fromTry' thực sự chặn, vì vậy không may mắn ở đó. – stefanobaghino

8

Theo tôi: Cố gắng & Tương lai là một công trình monadic và thành ngữ cách để là thành phần monadic (ví-hiểu):

đó bạn cần phải xác định biến đơn nguyên cho tương lai [Hãy thử [_]] (mã cho thư viện của bạn):

case class FutureT[R](run : Future[Try[R]])(implicit e: ExecutionContext) { 
    def map[B](f : R => B): FutureT[B] = FutureT(run map { _ map f }) 
    def flatMap[B](f : R => FutureT[B]): FutureT[B] = { 
    val p = Promise[Try[B]]() 
    run onComplete { 
     case Failure(e)   => p failure e 
     case Success(Failure(e)) => p failure e 
     case Success(Success(v)) => f(v).run onComplete { 
     case Failure(e)   => p failure e 
     case Success(s)   => p success s 
     } 
    } 
    FutureT(p.future) 
    } 
} 

object FutureT { 
    def futureTry[R](run : => Try[R])(implicit e: ExecutionContext) = 
    new FutureT(future { run }) 

    implicit def toFutureT[R](run : Future[Try[R]]) = FutureT(run) 
    implicit def fromFutureT[R](futureT : FutureT[R]) = futureT.run 
} 

và ví dụ sử dụng:

def blockMethod(x: Int): Try[Int] = Try { 
    Thread.sleep(5000) 
    if(x < 10) throw new IllegalArgumentException 
    else x + 1 
} 

import FutureT._ 

// idiomatic way :) 
val async = for { 
    x <- futureTry { blockMethod(15) } 
    y <- futureTry { blockMethod(25) }    
} yield (x + y) * 2 // possible due to using modan transformer 

println("Waiting... 10 seconds to complete") 

val res = Await.result(async, 20 seconds) 
println(res) 

// example with Exception 
val asyncWithError = for { 
    x <- futureTry { blockMethod(5) } 
    y <- futureTry { blockMethod(25) }    
} yield (x + y) * 2 // possible due to using modan transformer 

// Can't use Await because will get exception 
// when extract value from FutureT(Failure(java.lang.IllegalArgumentException)) 
// no difference between Failure produced by Future or Try 
asyncWithError onComplete { 
    case Failure(e) => println(s"Got exception: $e.msg") 
    case Success(res) => println(res) 
} 
// Output: 
// Got exception: java.lang.IllegalArgumentException.msg 
+0

có lỗi ở đâu đó. thay đổi 'blockMethod (15)' bởi 'blockMethod (5)' kết quả trong một ngoại lệ kết thúc chương trình, và dòng cuối cùng 'println (res)' không được thực thi. –

+0

Cảm ơn bạn David, tôi đã bỏ lỡ mô tả về hành vi Ngoại lệ, hãy cập nhật câu trả lời của tôi với ví dụ Ngoại lệ. – Yuriy

Các vấn đề liên quan