2012-05-14 43 views
7

Tôi đang cố hiểu tương lai Clojure và tôi đã xem các ví dụ từ các sách Clojure phổ biến ở đó, và có những ví dụ về tương lai được sử dụng để tính toán song song (có vẻ hợp lý).hiểu tương lai Clojure

Tuy nhiên, tôi hy vọng ai đó có thể giải thích hành vi của một ví dụ đơn giản được điều chỉnh từ cuốn sách Lập trình Clojure của O'Reilly.

(def long-calculation (future (apply + (range 1e8)))) 

Khi tôi cố gắng dereference này, bằng cách làm

(time @long-calculation) 

Nó trả về kết quả đúng (4999999950000000), nhưng hầu như ngay lập tức (trong 0,045 msecs) trên máy tính của tôi.

Nhưng khi tôi gọi hàm thực tế, như vậy

(time (apply + (range 1e8))) 

tôi nhận được kết quả chính xác là tốt, nhưng thời gian thực hiện là lớn hơn nhiều (~ 5000 msecs).

Khi tôi dereference tương lai, sự hiểu biết của tôi là một thread mới được tạo ra trên đó biểu thức được đánh giá - trong trường hợp này tôi mong đợi nó sẽ mất khoảng 5000 msec là tốt.

Làm thế nào mà tương lai không quan tâm trả về kết quả chính xác nhanh như vậy?

Trả lời

11

Tính toán trong tương lai sẽ bắt đầu ngay sau khi bạn tạo tương lai (trong một chuỗi riêng biệt). Trong trường hợp của bạn, việc tính toán bắt đầu ngay sau khi bạn thực hiện (def long-calculation ....)

dereferencing sẽ làm một trong hai điều:

  • Nếu tương lai vẫn chưa hoàn thành, khối cho đến khi nó hoàn thành và sau đó trả về giá trị (điều này có thể mất một khoảng thời gian tùy ý hoặc thậm chí không bao giờ hoàn thành nếu tương lai không chấm dứt)
  • Nếu tương lai đã hoàn thành, hãy trả lại kết quả. Đây là gần như tức thời (đó là lý do tại sao bạn đang nhìn thấy lợi nhuận dereference rất nhanh)

Bạn có thể nhìn thấy hiệu quả bằng cách so sánh như sau:

;; dereference before future completes 
(let [f (future (Thread/sleep 1000))] 
    (time @f)) 
=> "Elapsed time: 999.46176 msecs" 

;; dereference after future completes 
(let [f (future (Thread/sleep 1000))] 
    (Thread/sleep 2000) 
    (time @f)) 
=> "Elapsed time: 0.039598 msecs" 
+0

Có một bất lợi cho việc sử dụng một số lượng lớn tương lai? Tôi đã viết một số mã thực hiện tính toán số lượng lớn ở một số địa điểm. Thay vì sử dụng các mảng Java bản địa hoặc làm kiểu gợi ý, tôi có thể viết mã chức năng thành ngữ và 'tương lai' các kết quả của các tính toán này thay thế không? – endbegin

+2

Tương lai là khá nhẹ nhưng có một số chi phí, vì vậy tôi sẽ tránh sử dụng chúng cho các tính toán cực kỳ nhỏ. Nếu bạn muốn thực hiện tính toán song song, hãy cân nhắc sử dụng 'pmap' - đây là phiên bản đồng thời của' map' sử dụng tương lai dưới mui xe. Có nói rằng, nếu mã của bạn thực sự là số lượng chuyên sâu bạn có lẽ tốt nhất bằng cách sử dụng cả hai mảng Java * và * pmap/tương lai nếu bạn muốn nhận được t ông tốt nhất trong thời gian CPU của bạn. – mikera

+0

Tôi đã cố gắng để chơi xung quanh với pmap, nhưng đã tìm thấy nó hữu ích chỉ khi kích thước dữ liệu là "lớn" (bao nhiêu là hơi chủ quan, tất nhiên). Tôi đã học Clojure bằng cách thực hiện một số chức năng xử lý tín hiệu số đơn giản, và có một lợi thế tốc độ đáng chú ý với việc sử dụng các mảng Java bản địa trên một kiểu chức năng với trừu tượng seq trong chế độ xử lý/luồng đơn. Nếu tôi sử dụng tương lai, tốc độ tăng lên rất lớn đến nỗi việc sử dụng mã nguồn gốc hoặc chức năng có thực sự không quan trọng. Cảm thấy như tôi đang thiếu một cái gì đó hiển nhiên. – endbegin

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