- vừa được xem lúc

Định nghĩa cấu trúc tiết kiệm bộ nhớ và tối ưu hoá đọc cho CPU trong Golang

0 0 17

Người đăng: Ngọc Nguyễn Đức

Theo Viblo Asia

Nguồn bài viết

Định nghĩa cấu trúc

Cấu trúc là 1 kiểu dữ liệu tập hợp của các field, hiệu quả trong việc gom data liên quan thành 1 record. Điều này cho phép tất cả dữ liệu liên quan đến một thực thể được gói gọn trong một định nghĩa lightweight, các hành vi có thể được thực hiện bằng cách xác định các chức năng trên kiểu cấu trúc.

Trong bài viết này sẽ giải thích cách định nghĩa cấu trúc hiệu quả về sử dụng memory và CPU Cycles

Trước khi optimized

Chúng ta hãy xem xét cấu trúc này bên dưới, định nghĩa về terraform resource cho một số use-case:

type TerraformResource struct { Cloud string // 16 bytes Name string // 16 bytes HaveDSL bool // 1 byte PluginVersion string // 16 bytes IsVersionControlled bool // 1 byte TerraformVersion string // 16 bytes ModuleVersionMajor int32 // 4 bytes
}

Hãy cùng kiểm tra xem sẽ mất bao nhiêu dung lượng bộ nhớ cần để cấp phát cho mỗi cấu trúc TerraformResource sử dụng đoạn mã sau

package main import "fmt"
import "unsafe" type TerraformResource struct { Cloud string // 16 bytes Name string // 16 bytes HaveDSL bool // 1 byte PluginVersion string // 16 bytes IsVersionControlled bool // 1 byte TerraformVersion string // 16 bytes ModuleVersionMajor int32 // 4 bytes
} func main() { var d TerraformResource d.Cloud = "aws" d.Name = "ec2" d.HaveDSL = true d.PluginVersion = "3.64" d.TerraformVersion = "1.1" d.ModuleVersionMajor = 1 d.IsVersionControlled = true fmt.Println("==============================================================") fmt.Printf("Total Memory Usage StructType:d %T => [%d]\n", d, unsafe.Sizeof(d)) fmt.Println("==============================================================") fmt.Printf("Cloud Field StructType:d.Cloud %T => [%d]\n", d.Cloud, unsafe.Sizeof(d.Cloud)) fmt.Printf("Name Field StructType:d.Name %T => [%d]\n", d.Name, unsafe.Sizeof(d.Name)) fmt.Printf("HaveDSL Field StructType:d.HaveDSL %T => [%d]\n", d.HaveDSL, unsafe.Sizeof(d.HaveDSL)) fmt.Printf("PluginVersion Field StructType:d.PluginVersion %T => [%d]\n", d.PluginVersion, unsafe.Sizeof(d.PluginVersion)) fmt.Printf("ModuleVersionMajor Field StructType:d.IsVersionControlled %T => [%d]\n", d.IsVersionControlled, unsafe.Sizeof(d.IsVersionControlled)) fmt.Printf("TerraformVersion Field StructType:d.TerraformVersion %T => [%d]\n", d.TerraformVersion, unsafe.Sizeof(d.TerraformVersion)) fmt.Printf("ModuleVersionMajor Field StructType:d.ModuleVersionMajor %T => [%d]\n", d.ModuleVersionMajor, unsafe.Sizeof(d.ModuleVersionMajor)) }

Link execute

Output

==============================================================
Total Memory Usage StructType:d main.TerraformResource => [88]
==============================================================
Cloud Field StructType:d.Cloud string => [16]
Name Field StructType:d.Name string => [16]
HaveDSL Field StructType:d.HaveDSL bool => [1]
PluginVersion Field StructType:d.PluginVersion string => [16]
ModuleVersionMajor Field StructType:d.IsVersionControlled bool => [1]
TerraformVersion Field StructType:d.TerraformVersion string => [16]
ModuleVersionMajor Field StructType:d.ModuleVersionMajor int32 => [4]

Tổng dung lượng bộ nhớ cần cấp phát cho struct TerraformResource88 bytes. Hình dưới đây sẽ mô tả cách mà bộ nhớ được cấp phát

images

Tuy nhiên hãy nhìn lại 1 chút 16 + 16 + 1 + 16 + 1 + 16 + 4 = 70, vậy 18 bytes còn lại phát sinh từ đâu?

Khi nói đến memory allocation cho kiểu structs, chúng luôn luôn được cấp phát liền kề, liên tục bởi các byte-aligned blocks của bộ nhớ, mỗi field sẽ được cấp phát và lưu trữ theo thứ tự mà nó được định nghĩa bên trong cấp trúc. Khái niệm byte-alignment trong ngữ cảnh này có nghĩa là các khối bộ nhớ liền kề, liên tục được căn chỉnh ở các block bằng với word size của nền tảng (trong trường hợp này mỗi block là 8 bytes).

images

Chúng ta có thể thấy rõ rằng TerraformResource.HaveDSL , TerraformResource.isVersionControlledTerraformResource.ModuleVersionMajor chỉ được chiếm dữ tương ứng 1 Byte, 1Byte4 Bytes. Phần còn lại của không gian được lấp đầy bằng empty pad bytes.

Allocation bytes =16 bytes+16 bytes+ 1 bytes+ 16 bytes+ 1 bytes+ 16 bytes+ 4 bytes = 70 bytes

Empty Pad bytes = 7 bytes + 7 bytes + 4 bytes = 18 bytes

Total bytes = Allocation bytes + Empty Pad bytes = 70 bytes + 18 bytes = 88 bytes

Sau khi optimized

Vậy làm thế nào để sửa nó. Với data structure alignment phù hợp điều gì sẽ xảy ra nếu chúng ta định nghĩa lại cấu trúc như sau

type TerraformResource struct { Cloud string // 16 bytes Name string // 16 bytes PluginVersion string // 16 bytes TerraformVersion string // 16 bytes ModuleVersionMajor int32 // 4 bytes HaveDSL bool // 1 byte IsVersionControlled bool // 1 byte
}

Chạy lại đoạn code giống ban đầu sau khi struct được optimized

package main import "fmt"
import "unsafe" type TerraformResource struct { Cloud string // 16 bytes Name string // 16 bytes PluginVersion string // 16 bytes TerraformVersion string // 16 bytes ModuleVersionMajor int32 // 4 bytes HaveDSL bool // 1 byte IsVersionControlled bool // 1 byte
} func main() { var d TerraformResource d.Cloud = "aws" d.Name = "ec2" d.HaveDSL = true d.PluginVersion = "3.64" d.TerraformVersion = "1.1" d.ModuleVersionMajor = 1 d.IsVersionControlled = true fmt.Println("==============================================================") fmt.Printf("Total Memory Usage StructType:d %T => [%d]\n", d, unsafe.Sizeof(d)) fmt.Println("==============================================================") fmt.Printf("Cloud Field StructType:d.Cloud %T => [%d]\n", d.Cloud, unsafe.Sizeof(d.Cloud)) fmt.Printf("Name Field StructType:d.Name %T => [%d]\n", d.Name, unsafe.Sizeof(d.Name)) fmt.Printf("HaveDSL Field StructType:d.HaveDSL %T => [%d]\n", d.HaveDSL, unsafe.Sizeof(d.HaveDSL)) fmt.Printf("PluginVersion Field StructType:d.PluginVersion %T => [%d]\n", d.PluginVersion, unsafe.Sizeof(d.PluginVersion)) fmt.Printf("ModuleVersionMajor Field StructType:d.IsVersionControlled %T => [%d]\n", d.IsVersionControlled, unsafe.Sizeof(d.IsVersionControlled)) fmt.Printf("TerraformVersion Field StructType:d.TerraformVersion %T => [%d]\n", d.TerraformVersion, unsafe.Sizeof(d.TerraformVersion)) fmt.Printf("ModuleVersionMajor Field StructType:d.ModuleVersionMajor %T => [%d]\n", d.ModuleVersionMajor, unsafe.Sizeof(d.ModuleVersionMajor))
}

Link execute

Output

==============================================================
Total Memory Usage StructType:d main.TerraformResource => [72]
==============================================================
Cloud Field StructType:d.Cloud string => [16]
Name Field StructType:d.Name string => [16]
HaveDSL Field StructType:d.HaveDSL bool => [1]
PluginVersion Field StructType:d.PluginVersion string => [16]
ModuleVersionMajor Field StructType:d.IsVersionControlled bool => [1]
TerraformVersion Field StructType:d.TerraformVersion string => [16]
ModuleVersionMajor Field StructType:d.ModuleVersionMajor int32 => [4]

Bây giờ tổng bộ nhớ được cấp phát cho kiểu TerraformResource72 bytes. Hãy cùng nhìn xem cách mà bộ nhớ liên kết

images

Chỉ bằng cách sửa các thành phần của struct phù hợp với data structure alignment, chúng ta đã có thể giảm dung lượng bộ nhớ từ 88 bytes xuống còn 72 bytes ...wow!

Cùng check lại 1 chút

Allocation bytes =16 bytes+16 bytes+ 1 bytes+ 16 bytes+ 1 bytes+ 16 bytes+ 4 bytes = 70 bytes

Empty Pad bytes = 2 bytes

Total bytes = Allocation bytes + Empty Pad bytes = 70 bytes + 2 bytes = 72 bytes

data structure alignment không chỉ giúp chúng ta sử dụng bộ nhớ hiệu quả mà còn với Chu kỳ đọc của CPU….

CPU đọc bộ nhớ theo từng words, 4 bytes trên 32-bit, 8 bytes trên 64-bit systems. Theo khai báo ban đầu của struct TerraformResource sẽ mất 11 bytes để CPU đọc tất cả

images

Tuy nhiên sau khi *optimized struct sẽ chỉ cần 9 Word theo hình dưới đây:

images

Bằng cách xác định đúng cấu trúc, dữ liệu được căn chỉnh theo cấu trúc, chúng ta có thể sử dụng cấp phát bộ nhớ một cách hiệu quả và giúp cho việc CPU đọc dữ liệu lưu bởi cấu trúc cũng nhanh chóng và hiệu quả.

Đây chỉ là một ví dụ nhỏ, hãy nghĩ về một cấu trúc lớn với 20 hoặc 30 trường với các kiểu khác nhau. Việc định nghĩa 1 cấu trúc chuẩn, phù hợp với cách mà data struct alignment thực sự mang lại hiệu quả cao...

Hy vọng blog này có thể làm sáng tỏ về cấu trúc bên trong, phân bổ bộ nhớ của chúng và chu kỳ đọc CPU cần thiết. Hi vọng điều nay có ich cho bạn!!

##Kết luận Hiểu rõ những kiến thức cơ bản sẽ giúp chúng ta viết code một cách có hiệu quả

Happy Coding!!

Bình luận

Bài viết tương tự

- vừa được xem lúc

gRPC - Nó là gì và có nên sử dụng hay không?

Nhân một ngày rảnh rỗi, mình ngồi đọc lại RPC cũng như gRPC viết lại để nhớ lâu hơn. Vấn đề là gì và tại sao cần nó .

0 0 112

- vừa được xem lúc

Embedded Template in Go

Getting Start. Part of developing a web application usually revolves around working with HTML as user interface.

0 0 40

- vừa được xem lúc

Tạo Resful API đơn giản với Echo framework và MySQL

1. Giới thiệu.

0 0 44

- vừa được xem lúc

Sử dụng goquery trong golang để crawler thông tin các website Việt Nam bị deface trên mirror-h.org

. Trong bài viết này, mình sẽ cùng mọi người khám phá một package thu thập dữ liệu có tên là goquery của golang. Mục tiêu chính của chương trình crawler này sẽ là lấy thông tin các website Việt Nam bị deface (là tấn công, phá hoại website, làm thay đổi giao diện hiển thị của một trang web, khi người

0 0 218

- vừa được xem lúc

Tạo ứng dụng craw dữ liệu bing với Golang, Mysql driver

Chào mọi người . Lâu lâu ta lại gặp nhau 1 lần, để tiếp tục series chia sẻ kiến thức về tech, hôm nay mình sẽ tìm hiểu và chia sẻ về 1 ngôn ngữ đang khá hot trong cộng đồng IT đó là Golang.

0 0 59

- vừa được xem lúc

Golang: Rest api and routing using MUX

Routing with MUX. Let's create a simple CRUD api for a blog site. # All . GET articles/ .

0 0 39