Một số kĩ thuật tối ưu tốc độ Swift
Bài đăng này đã không được cập nhật trong 3 năm
1. Khởi động whole module optimization
Ở Xcode7 thì chúng ta có thể khởi động Whole Module Optimization trong build setting để có thể tối ưu tốc độ của Swift.
Đối với cấp độ None hoặc Fast thì trình biên dịch làm việc với từng file source một. Khi định nghĩa các generic function trong một file
Đối với Whole Module Optimization cho phép trình biên dịch biết được tất cả các file trong một module. Điều này khiến cho trình biên dịch tối ưu các generic function mặc dù nó ở các file source khác nhau.
2. Sử dụng struct thay cho class
Thử nghiệm bằng 1 class và một struct có cấu trúc tương tự sau:
class Person {
let name: String
let age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
func example() {
var x = CFAbsoluteTimeGetCurrent()
var array = [Person]()
for _ in 0..<100000 {
array.append(Person(name: "Foo", age: 30))
}
for n in 0..<100000 {
let _ = array[n]
}
x = (CFAbsoluteTimeGetCurrent() - x) * 1000.0
print("Took \(x) milliseconds")
}
Ta thấy có dòng giá trị của x được hiển thị trên màn hình console thì số nhỏ nhất sau nhiều lần thử nghiệm là 51.9 milliseconds tuy nhiên sử dụng hàm tương tự với struct ta thấy có hiệu quả đáng kể
struct Person {
let name: String
let age: Int
}
func example() {
var x = CFAbsoluteTimeGetCurrent()
var array = [Person]()
for _ in 0..<100000 {
array.append(Person(name: "Foo", age: 30))
}
for n in 0..<100000 {
let _ = array[n]
}
x = (CFAbsoluteTimeGetCurrent() - x) * 1000.0
print("Took \(x) milliseconds")
}
Swift ra đời hỗ trợ tốt cho việc sử dụng struct, thực tế class hơn struct là có thêm ARC hỗ trợ việc nhiều biến cùng reference nên nếu chúng ta không thực sự cần việc đó thì nên dùng struct để tối ưu cho tốc độ của chương trình.
3. Sử dụng từ khoá final trước các khai báo không bị override
Sử dụng từ khoá final khi chắc chắc thuộc tính, phương thức của class không được override. Việc này sẽ hỗ trợ cho swift trong quá trình xử lý, compiler code. Ví dụ với một đoạn code đơn giản sau
class Animal {
func move() {
if "Foo".characters.count > 0 {
let a = 1
let b = 2
let c = a + b
print("\(c)")
}
}
}
class Dog: Animal {
}
func example() {
var x = CFAbsoluteTimeGetCurrent()
var array = [Dog]()
for n in 0..<100000 {
array.append(Dog())
array[n].move()
}
x = (CFAbsoluteTimeGetCurrent() - x) * 1000.0
print("Took \(x) milliseconds")
}
Nếu chúng ta thêm từ khoá final vào trước khai báo fuction move() của class Animal và kiểm tra chúng ta cũng thấy giá trị đã được tối ưu thêm khá nhiều.
4. Sử dụng các tiền điều kiện cho vòng lặp
Thông thường chúng ta sẽ thực hiện việc chạy vòng lặp for với giới hạn trên xác định là giá trị của một hằng số, số đếm của một mảng hay một giá trị nào đó. Tuy nhiên nếu chúng ta thực kiểm tra tiền điều kiện cho biết giới hạn trên thì sẽ tối ưu được vòng lặp lên rất nhiều. Với ví dụ đơn giản sau:
func example() {
var x = CFAbsoluteTimeGetCurrent()
var array = [Person]()
for _ in 0..<100000 {
array.append(Person(name: "Foo", age: 30))
}
for n in 0..<array.count {
let _ = array[n]
}
x = (CFAbsoluteTimeGetCurrent() - x) * 1000.0
print("Took \(x) milliseconds")
}
func example2() {
var x = CFAbsoluteTimeGetCurrent()
var array = [Person]()
for _ in 0..<100000 {
array.append(Person(name: "Foo", age: 30))
}
let a = array.count
precondition(a <= array.count)
for n in 0..<a {
let _ = array[n]
}
x = (CFAbsoluteTimeGetCurrent() - x) * 1000.0
print("Took \(x) milliseconds")
}
Bạn sẽ thấy hiệu quả của chúng.
Tổng kết
Với bất kì một đoạn code nào đó chúng ta hãy luôn tự nghĩ trong đầu xem liệu đó có phải tối ưu chưa, liệu nó có thể giúp cho chương trình của chúng ta chạy ổn chưa hay nó còn đang thực hiện quá nhiều thao tác thừa. Mặc dù phần cứng đang càng ngày càng mạnh mẽ tuy nhiên nếu chúng ta cải thiện được suy nghĩ của bản thân về chính các đoạn code của mình viết ra thì chương trình sẽ được cải thiện tốc độ đáng kể.
All rights reserved