Hiệu suất của các collection immutable trong scala

Mutable collection thường nhanh hơn một immutable bởi vì nó đang làm việc trên cùng một địa chỉ bộ nhớ. Do đó, dữ liệu sẽ không bị copy đi, copy lại. Trong Scala, vấn đề này có thể được giảm nhẹ bằng cách sử dụng lại các object giống như một vài hoạt động của List

Chỉ có một instace của list đang nắm giữ các số 1, 2 và 3. Giá trị ‘a’ có một tham chiếu trỏ đến phần tử cuối cùng của List. Giá trị ‘c’ có một tham chiếu trỏ đến phần tử đầu tiên của List. Bởi vì list là một immutable, chúng ta không thể thay đổi giá trị của list, giúp nó an toàn để chia sẻ cùng một list cho cả 3 giá trị khác nhau (chúng ta chỉ nhìn thấy phần khác nhau của list)

2 cấu trúc dữ liệu thông thường mà hầu hết chúng ta sử dụng hàng ngày đó là map và list. Mảng trong Scala là mutable, nên, chúng ta sẽ không đề cập đến nó vì nó cũng giống như mảng trong Java

Chúng ta sẽ sử dụng Scalameter để đo benchmark bởi vì cài đặt nó tương đối đơn giản. Đây là cách cấu hình.

Map

Giả sử chúng ta có 2 case class đang giữ các immutable và mutable của map như sau.

Hãy tạo một range valrange= (1 to 1000), và sử dụng foldLeft để gán từng số trong range vào map

Bạn có thể nói rằng một mutable nhanh hơn một immutable. Nhưng chúng ta chỉ muốn biết liệu nó có nhanh hơn đáng kể hay không thôi. Một điểm thú vị là timeMap3 sử dụng dữ liệu mutable và cuối cùng sẽ chuyển đổi thành immutable.

Chắc chắn, chúng ta nên sử dụng immutable map mặc dù nó chậm hơn gấp 3 lần mutable. Chênh lệch 0.3 ms là quá nhỏ để cân nhắc. Nếu bạn đang phát triển một hệ thống thời gian thực, thì con số này không hề nhỏ. Nhưng, thực tế nếu bạn làm việc trên hệ thống thời gian thực, nơi mà 0.3 ms được coi là đáng kể, thì bạn không nên lựa chọn Scala ngay từ lúc đầu. Chi phí cho hàm chuyển đổi toMap mất 0.6 ms do đó làm cho tổng thời gian cao hơn cả immutable map.

Nếu bạn xem code thực thi hàm toMap, bạn sẽ thấy rằng nó tạo một immutable map hoàn toàn mới. Đó là lý do tại sao nó mất 0.5ms

List

Hãy nhìn list, một cấu trúc dữ liệu khác thường được sử dụng.

Kết qủa như sau

immutable list thực hiện chậm hơn mutable list 362 lần. Nó thật là khủng khiếp vì giá trị N chỉ là 1000 và hiệu suất của nó sẽ tồi tệ như thế nào nếu N là 2000

Bây giờ thì khoảng cách còn lớn hơn. Immutable list chậm hơn mutable list 610 lần.

Khi bạn đang xử lý một List dữ liệu lớn, bạn có thể nên sử dụng một mutable list rồi sau đấy chuyển đổi nó thành immutable list, giúp đảm bảo rằng bạn không chia sẽ dữ liệu mutable

Tôi muốn nhắc bạn một điều quan trọng là chúng ta đang thực hiện benchmark trên các hành động thêm vào. Scala list được thực thi như list liên kết đơn, chi phí của các hành động thêm vào làm thời gian lâu hơn. Nếu bạn muốn tìm hiểu thêm về các đặc tính của Scala collection, bài viết này, được tạo bởi Li Haoyi, rất hay và chi tiết.

Chúng ta biết rằng nhược điểm hoạt động :: mất một lượng thời gian, nó nhanh như chớp bởi vì chúng ta thêm một phần tử vào đầu list. Dựa trên thực tế này, hãy thử làm cái gì đó thú vị với nó

Chúng ta sẽ thử đo lai các hàm này một lần nữa. Nhưng lúc này chúng ta sẽ dùng hoạt động :: và sắp xếp đảo ngược immutable list để có được kết quả giống như hàm thêm vào các phần tử. Tôi chắc chắn rằng kết quả benchmark sẽ khiến bạn ngạc nhiên

Kết quả như sau

Chú ý rằng hàm reverse cũng sử dụng :: . Hàm này được thực hiện sử dụng một cách tiếp cận bắt buộc là sử dụng vòng lặp while và 2 biến tạm thời với mục đích hiệu suất. Những gì nó làm chỉ đơn giản là thay đổi địa chỉ của con trỏ trong list liên kết đơn. Mặc dù phép tính reserve nhận được O(n). Hiệu suất thực tế là đáng kinh ngạc.

Nếu bạn không muốn gọi hàm reverse, bạn có thể dùng foldRight thay thế

Thông thường, chúng ta thích sử dụng foldLeft hơn foldRight, nếu thứ tự là không quan trọng. Bởi vì foldRight sẽ đảo ngược thứ tự trước khi gọi hàm foldLeft trong khi chạy

Đây là code thực hiện hàm foldRight

 

 

You May Also Like

About the Author: Nguyen Dinh Thuc

Leave a Reply

avatar
  Subscribe  
Notify of