Chú ý khi dùng for comprehension với Future trong scala
Scala
50
White

huydx viết ngày 15/06/2015

Nãy mình có trao đổi trên scala group trên facebook và nhận thấy một điểm cơ bản cực dễ nhầm khi dùng Future trong scala.
Có đoạn code dưới đây

import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.util.{Success,Failure}
import scala.collection.immutable._

object Foo extends App {
  def test1 = Future {
      Thread.sleep(2000)
      "test1"
    }


  def test2 =
    Future {
      Thread.sleep(2000)
      "test2"
    }

  println(Await.result(
    for {
      v1 <- test1
      v2 <- test2
    } yield { v1 + v2 }, 2 seconds))

}

Theo các bạn thì việc chạy đoạn code trên sẽ diễn ra thế nào, tuần tự hay song song?
Nếu song song thì đoạn code sẽ kết thúc trong 2s, và kết quả chúng ta mong đợi sẽ là "test1test2"

Đây là kết quả khi chạy đoạn code trên:

error java.util.concurrent.TimeoutException: Futures timed out after [2 seconds]
java.util.concurrent.TimeoutException: Futures timed out after [2 seconds]

Như vậy là test1 và test2 không được chạy song song, điều gì đã khiến cho chúng bị diễn ra tuần tự?
Thủ phạm chính là def. Việc sử dụng def khiến cho việc execute đoạn code bên trong chỉ được diễn ra tại thời điểm gọi, kết hợp với việc for comprehension trong scala lại được compile thành nest flatMap :

test1 flatMap { v1 => { test2 flatMap { v2 } } 

Do đó mà test2 Future được tạo ra sau khi test1 đã được execute xong, khiến cho việc xử lý bị thành tuần tự.

Cách giải quyết khá đơn giản, thay vì dùng def thì chúng ta dùng val để tạo Future placeholder trước.

  val test1 = Future {
      Thread.sleep(2000)
      "test1"
    }


  val test2 =
    Future {
      Thread.sleep(2000)
      "test2"
    }

Ngoài ra chúng ta cũng có thê dùng zip hoặc là Future.sequence

test1 zip test2 onComplete { case Success(v) => v._1 + v._2 }
Future.sequence(List(test1, test2))

Đây là một cái bẫy khá nguy hiểm mà có thể khiến chúng ta có những xử lý tưởng là song song, nhưng thực ra là tuần tự, nên cần chú ý.

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

huydx

118 bài viết.
1045 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
164 15
Introduction (Link) là một cuộc thi ở Nhật, và cũng chỉ có riêng ở Nhật. Đây là một cuộc thi khá đặc trưng bởi sự thú vị của cách thi của nó, những...
huydx viết 2 năm trước
164 15
White
144 14
Một ngày đẹp trời, bạn quyết định viết một dịch vụ web dự định sẽ làm thay đổi cả thế giới. Dịch vụ của bạn sẽ kết nối tất cả các thiết bị di động ...
huydx viết 2 tháng trước
144 14
White
133 15
Happy programmer là gì nhỉ, chắc ai đọc xong title của bài post này cũng không hiểu ý mình định nói đến là gì :D. Đầu tiên với cá nhân mình thì hap...
huydx viết hơn 3 năm trước
133 15
Bài viết liên quan
White
10 0
Kí tự Regex cơ bản Về cơ bản thì các sử lý matching của scala.util.matching.Regex sẽ được "phó thác" (delegate) cho java Regex. Bạn có thể tạo một ...
huydx viết hơn 3 năm trước
10 0
White
7 1
Trong scala kí tự _ được dùng với khá nhiều mục đích .. không liên quan đến nhau. Tạm note lại cái đã khi nào có time sẽ quay lại viết cẩn thận sa...
huydx viết hơn 3 năm trước
7 1
White
1 0
(Bài viết hơi khó hiểu, dành cho bạn nào có hứng thú với type programming trong scala với các thư viện như shapeless chẳng hạn) Thông thường với m...
huydx viết hơn 2 năm trước
1 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
118 bài viết.
1045 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!