Skip to content

Commit d014f4a

Browse files
committed
update chap02
2 parents 7d8432e + 37fdb3e commit d014f4a

File tree

86 files changed

+311598
-973
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+311598
-973
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.idea
2-
.vscode
2+
.vscode
3+
.txt

ch1-basic/README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,15 @@
99
</div>
1010
<br/>
1111

12-
>*Tôi không biết tại sao bạn lại không vui trong suốt 10 năm qua. Nhưng hãy tin tôi đi, xóa bỏ đi những nặng nhọc trong quá khứ, dùng ngôn ngữ Go và trải nghiệm niềm hạnh phúc bắt đầu!*
13-
14-
>*Những viên gạch nhỏ được đóng góp cuối cùng sẽ xây được một lâu đài kiên cố - Xiao Zhang*
12+
>*“Go is no Erlang, Smalltalk or Scheme, nothing pure. But it works great and is fun!” – Frank Mueller (@themue)"*
1513
1614
Chương này bắt đầu bằng vài lời giới thiệu về lịch sử của ngôn ngữ Go và phân tích chi tiết cuộc cách mạng của chương trình "Hello World" với những thế hệ ngôn ngữ đi trước. Sau đó, một số cấu trúc dữ liệu sẽ được trình bày như `arrays`, `strings`, và `slices`, tính chất `process-oriented``duck typing` được thể hiện qua `functions`, `methods`, và `interfaces`, đặc biệt là mô hình `concurrent programming``error handling` cũng được giới thiệu sơ qua. Cuối cùng, một số trọng tâm trong việc phát triển chương trình trên các nền tảng macOS, Windows, và Linux, cũng như một vài editor và môi trường phát triển tích hợp (IDE) cũng được đề cập, bởi vì có công cụ tốt thì năng suất làm việc mới tăng lên.
15+
16+
Quyển sách này được xác định là một trong những quyển sách nâng cao về Golang, vì vậy người đọc cần có một nền tảng Golang nhất định. Nếu bạn không biết nhiều về Golang, tác giả khuyên bạn nên học Golang với một số gợi ý sau.
17+
18+
- Sau khi cài đặt Golang và tải hướng dẫn bằng `go get golang.org/x/tour`, có thể xem hướng dẫn [A Tour of Go](https://tour.golang.org/welcome/1) ngay ở local bằng lệnh `tour`.
19+
- Bạn cũng có thể đọc hướng dẫn ["Ngôn ngữ lập trình Go"](http://www.gopl.io/) được xuất bản bởi team Golang chính thức . ["Ngôn ngữ lập trình Go"](http://www.gopl.io/) được gọi là *Kinh thánh* Golang trong cộng đồng Golang mà bạn phải đọc thật bài bản.
20+
21+
Trong khi học, hãy cố gắng giải quyết một số vấn đề nhỏ với Golang. Nếu bạn muốn tham khảo API, có thể mở truy vấn tài liệu tích hợp bằng lệnh `godoc`.
22+
23+
Từ thời điểm này chúng ta sẽ mặc định rằng bạn có thể sử dụng Golang một cách thuần thục.

ch1-basic/ch1-01-genesis.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Ngôn ngữ [Go](https://golang.org/) ban đầu được thiết kế và phát triển bởi một nhóm kĩ sư Google bao gồm **Robert Griesemer**, **Ken Thompson****Rob Pike** vào năm 2007. Mục đích của việc thiết kế ngôn ngữ mới bắt nguồn từ một số phản hồi về tính chất phức tạp của C++11 và nhu cầu thiết kế lại ngôn ngữ C trong môi trường network và multi-core.
44

5-
Vào giữa năm 2008, hầu hết các tính năng được thiết kế trong ngôn ngữ được hoàn thành, họ bắt đầu hiện thực trình biên dịch (compiler) và bộ thực thi (runtime) với **Russ Cox** là nhà phát triển chính. Trước năm 2010, ngôn ngữ Go dần dần được hoàn thiện. Vào tháng 9 cùng năm, ngôn ngữ Go chính thức được công bố dưới dạng Open source.
5+
Vào giữa năm 2008, hầu hết các tính năng được thiết kế trong ngôn ngữ được hoàn thành, họ bắt đầu hiện thực trình biên dịch (compiler) và Go runtime với **Russ Cox** là nhà phát triển chính. Trước năm 2010, ngôn ngữ Go dần dần được hoàn thiện. Vào tháng 9 cùng năm, ngôn ngữ Go chính thức được công bố dưới dạng Open source.
66

77
Ngôn ngữ Go thường được mô tả là "Ngôn ngữ tựa C" hoặc là "Ngôn ngữ C của thế kỉ 21". Từ nhiều khía cạnh, ngôn ngữ Go thừa hưởng những ý tưởng từ ngôn ngữ C, như là cú pháp, cấu trúc điều khiển, kiểu dữ liệu cơ bản, thủ tục gọi, trả về, con trỏ, v,v.., hoàn toàn kế thừa và phát triển ngôn ngữ C, hình bên dưới mô tả sự liên quan của ngôn ngữ Go với các ngôn ngữ khác.
88

@@ -33,9 +33,9 @@ Một vài những tính năng khác của ngôn ngữ Go đến từ một số
3333

3434
Tính chất concurrency của Go đến từ học thuyết [Commutative sequential processes (CSP)](https://www.cs.cmu.edu/~crary/819-f09/Hoare78.pdf) được công bố bởi Tony Hoare tại Bell Labs vào năm 1978. Bài báo khoa học về CSP nói rằng chương trình chỉ là một tập hợp các tiến trình được chạy song song, mà không có sự chia sẻ về trạng thái, sử dụng `channel` cho việc giao tiếp và điều khiển đồng bộ.
3535

36-
Học thuyết CSP của Tony Hoare chỉ là một mô hình lập trình với những khái niệm cơ bản về concurrency (tính đồng thời), nó cũng không hẳn là một ngôn ngữ lập trình. Qua việc thiết kế Go, Rob Pike đã tổng hợp nhiều thập kỉ trong việc ứng dụng học thuyết CSP trong việc xây dựng ngôn ngữ lập trình.
36+
Học thuyết CSP của Tony Hoare chỉ là một mô hình lập trình với những khái niệm cơ bản về concurrency (tính đồng thời), nó cũng không hẳn là một ngôn ngữ lập trình. Qua việc thiết kế Go, Rob Pike đã tổng hợp nhiều thập kỷ trong việc ứng dụng học thuyết CSP trong việc xây dựng ngôn ngữ lập trình.
3737

38-
Ngôn ngữ [Erlang](https://en.wikipedia.org/wiki/Erlang_(programming_language)) là một hiện thực khác của học thuyết **CSP**.
38+
Ngôn ngữ **Erlang** là một hiện thực khác của học thuyết **CSP**, bạn có thể tìm kiếm thông tin về ngôn ngữ này trên [trang chủ Erlang](https://www.erlang.org/).
3939

4040
Hình dưới chỉ ra lịch sử phát triển của ngôn ngữ Go qua codebase logs.
4141

@@ -59,7 +59,7 @@ Có thể nhìn thấy từ những submission log rằng ngôn ngữ Go đượ
5959
</div>
6060
<br/>
6161

62-
Trong vòng những năm gần đây, Go là một ngôn ngữ được ưa chuộng khi viết các chương trình có kiến trúc Micro Services, vì những đặc tính nhỏ gọn, biên dịch nhanh, import thư viện từ github, cú pháp đơn giản nhưng hiện đại.
62+
Trong vòng những năm gần đây, Go là một ngôn ngữ được ưa chuộng khi viết các chương trình Micro Services, vì những đặc tính nhỏ gọn, biên dịch nhanh, import thư viện từ github, cú pháp đơn giản nhưng hiện đại.
6363

6464
## 1.1.2. Hello World
6565

@@ -77,7 +77,7 @@ import "fmt"
7777
// main là hàm đầu tiên được chạy
7878
func main() {
7979

80-
// in ra dòng chữ "Hello World"
80+
// in ra dòng chữ "Hello World"
8181
fmt.Println("Hello World")
8282
}
8383
```

ch1-basic/ch1-02-hello-revolution.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ Ngữ pháp của Alef về cơ bản giống như ngôn ngữ C. Nó có thể
210210
211211
## 1.2.5. Limbo - Sean Dorward, Phil Winterbottom, Rob Pike, 1995
212212
213-
Limbo (Hell) là ngôn ngữ lập trình để phát triển các ứng dụng phân tán chạy trên máy tính nhỏ. Nó hỗ trợ lập trình mô-đun, kiểm tra kiểu mạnh vào thời gian biên dịch và thời gian chạy, liên lạc bên trong process thông qua đường ống (pipeline), có bộ thu gom rác tự động. Có các loại dữ liệu trừu tượng đơn giản. Limbo được thiết kế để hoạt động an toàn ngay cả trên các thiết bị nhỏ mà không cần bảo vệ bộ nhớ phần cứng. Ngôn ngữ Limbo chạy chủ yếu trên hệ thống Inferno.
213+
Limbo (Hell) là ngôn ngữ lập trình để phát triển các ứng dụng phân tán chạy trên máy tính nhỏ. Nó hỗ trợ lập trình mô-đun, kiểm tra kiểu mạnh vào thời gian biên dịch và thời gian chạy, liên lạc bên trong process thông qua channel, có bộ thu gom rác tự động. Có các loại dữ liệu trừu tượng đơn giản. Limbo được thiết kế để hoạt động an toàn ngay cả trên các thiết bị nhỏ mà không cần bảo vệ bộ nhớ phần cứng. Ngôn ngữ Limbo chạy chủ yếu trên hệ thống Inferno.
214214
215215
Phiên bản Limbo của chương trình "Hello World" như sau:
216216

ch1-basic/ch1-03-array-string-and-slice.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ var decoder2 = [...]func(io.Reader) (image.Image, error){
125125
var unknown1 [2]interface{}
126126
var unknown2 = [...]interface{}{123, "Hello!"}
127127

128-
// Mảng pipe
128+
// Mảng channel
129129
var chanList = [2]chan int{}
130130
```
131131

@@ -142,16 +142,16 @@ var f = [...]int{}
142142

143143
Một array có chiều dài 0 thì không chiếm không gian lưu trữ.
144144

145-
## 1.3.2 String
145+
## 1.3.2. String
146146

147147
<div align="center">
148-
<img src="../images/1-3-string.jpeg" width="600">
148+
<img src="../images/ch1-string.png" width="400">
149149
</div>
150150
<br/>
151151

152152
`string` cũng là một array của các `byte` dữ liệu, nhưng khác với array những phần tử của string là [immutable](https://en.wikipedia.org/wiki/Immutable_object)
153153

154-
Cấu trúc `reflect.StringHeader` được định nghĩa với:
154+
Cấu trúc [reflect.StringHeader](https://golang.org/src/reflect/value.go?s=56526:56578#L1873) được dùng để biểu diễn string :
155155

156156
```go
157157
type StringHeader struct {
@@ -197,7 +197,7 @@ s1 := "hello world"[:5]
197197
s2 := "hello world"[6:]
198198
```
199199

200-
Tương tự như array, String cũng có một hàm build-in là `len` dùng để trả về chiều dài của string, ngoài ra bạn có thể dùng `reflect.StringHeader` để truy xuất chiều dài của string theo cách như sau
200+
Tương tự như array, String cũng có một hàm built-in là `len` dùng để trả về chiều dài của string, ngoài ra bạn có thể dùng `reflect.StringHeader` để truy xuất chiều dài của string theo cách như sau
201201

202202
```go
203203
fmt.Println("len(s): ", (*reflect.StringHeader)(unsafe.Pointer(&s)).Len)

ch1-basic/ch1-04-func-method-interface.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ Ta thường sử dụng `defer` cho việc đóng hoặc giải phóng tài ngu
8989
if err != nil {
9090
panic("cannot create file")
9191
}
92+
93+
// chắc chắn file sẽ được close dù hàm có bị panic hay return
9294
defer f.Close()
93-
// no matter what happens here file will be closed
94-
// for sake of simplicity I skip checking close result
9595
fmt.Fprintf(f,"hello")
9696
}
9797
```
@@ -135,6 +135,15 @@ Ta thường sử dụng `defer` cho việc đóng hoặc giải phóng tài ngu
135135

136136
### Slice trong Function
137137

138+
<div align="center">
139+
<img src="../images/slice_1.png" width="300">
140+
<br/>
141+
<span align="center">
142+
<i>Minh hoạ slice</i>
143+
</span>
144+
</div>
145+
<br/>
146+
138147
Mọi thứ trong Go đều được truyền theo kiểu pass by value, slice cũng thế. Nhưng vì giá trị của slice là một *header* (chứa con trỏ tới dữ liệu array bên dưới) nên khi truyền slice vào hàm, quá trình copy sẽ bao gồm luôn địa chỉ tới array chứa dữ liệu thực sự.
139148

140149
Ví dụ sau cho thấy ý nghĩa của việc truyền tham số kiểu slice vào hàm thay vì array:
@@ -263,7 +272,6 @@ func main() {
263272
Trong một số tình huống, ta quan tâm nhiều hơn đến một chuỗi thao tác ví dụ như `Read` đọc một số mảng và sau đó gọi `Close` để đóng, trong ngữ cảnh này, người dùng không quan tâm đến kiểu của đối tượng, miễn là nó có thể đáp ứng được các thao tác của `Read``Close`. Tuy nhiên trong các biểu thức phương thức của `ReadFile`, `CloseFile` có chỉ rõ kiểu `File` trong tham số kiểu sẽ khiến chúng không bị phụ thuộc vào đối tượng nào cụ thể. Việc này có thể khắc phục bằng cách sử dụng thuộc tính closure (closure property):
264273

265274
```go
266-
267275
func main() {
268276
var data []byte
269277
@@ -400,6 +408,14 @@ Duck-typing với ý tưởng đơn giản:
400408

401409
> If something looks like a duck, swims like a duck and quacks like a duck then it’s probably a duck.
402410

411+
<div align="center">
412+
<img src="../images/duck-typing.png" width="300">
413+
<br/>
414+
<span align="center">
415+
</span>
416+
</div>
417+
<br/>
418+
403419
Ví dụ có một interface con vịt, xác định khả năng `Quacks`:
404420

405421
```go

ch1-basic/ch1-05-mem.md

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@
22

33
Thời gian đầu, CPU chỉ có một lõi duy nhất, các ngôn ngữ khi đó sẽ theo mô hình lập trình tuần tự, điển hình là ngôn ngữ C. Ngày nay, với sự phát triển của công nghệ đa xử lý, để tận dụng tối đa sức mạnh của CPU, mô hình lập trình song song hay [multi-threading](https://en.wikipedia.org/wiki/Multithreading_(computer_architecture)) thường thấy trên các ngôn ngữ lập trình ra đời. Ngôn ngữ Go cũng phát triển mô hình lập trình song song rất hiệu quả với khái niệm Goroutines.
44

5-
<div align="center" width="600">
6-
<img src="../images/concurency.jpg">
7-
<br/>
8-
<span align="center"><i>Quá trình khởi tạo package</i></span>
9-
</div>
10-
<br/>
115

6+
Lập trình tuần tự|Lập trình song song
7+
---|---
8+
![](../images/ch1-5-sequence-programming.png) | ![](../images/ch1-5-parallelprograming.png)
129

1310
## 1.5.1. Goroutines và system threads
1411

@@ -17,15 +14,19 @@ Goroutines là một đơn vị concurrency của ngôn ngữ Go. Việc khởi
1714
Đầu tiên, system thread sẽ có một kích thước vùng nhớ stack cố định (thông thường vào khoảng 2MB). Vùng nhớ stack chủ yếu được dùng để lưu trữ những tham số, biến cục bộ và địa chỉ trả về khi chúng ta gọi hàm.
1815

1916
Kích thước cố định của stack sẽ dẫn đến hai vấn đề:
20-
* Lãng phí vùng nhớ đối với chương trình đơn giản
21-
* StackOverflow với những chương trình gọi hàm phức tạp.
17+
* Stack overflow với những chương trình gọi hàm đệ quy sâu.
18+
* Lãng phí vùng nhớ đối với chương trình đơn giản.
19+
2220

2321
Giải pháp cho vấn đề này chính là cấp phát linh hoạt vùng nhớ stack:
2422
* Một Goroutines sẽ được bắt đầu bằng một vùng nhớ nhỏ (khoảng 2KB hoặc 4KB).
2523
* Khi gọi đệ quy sâu (không gian stack hiện tại là không đủ) Goroutines sẽ tự động tăng không gian stack (kích thước tối đa của stack có thể được đạt tới 1GB)
2624
* Bởi vì chi phí của việc khởi tạo là nhỏ, chúng ta có thể dễ dàng giải phóng hàng ngàn goroutines.
2725

28-
Bộ thực thi (runtime) Go có riêng cơ chế định thời cho Goroutines, nó dùng một số kỹ thuật để ghép M Goroutines trên N thread của hệ thống. Cơ chế định thời Goroutines tương tự với cơ chế định thời của `kernel` nhưng chỉ ở mức chương trình. Biến `runtime.GOMAXPROCS` quy định số lượng system thread hiện thời chạy trên các Goroutines.
26+
Go runtime có riêng cơ chế định thời cho Goroutines, nó dùng một số kỹ thuật để ghép M Goroutines trên N thread của hệ thống. Cơ chế định thời Goroutines tương tự với cơ chế định thời của `kernel` nhưng chỉ ở mức chương trình. Biến `runtime.GOMAXPROCS` quy định số lượng system thread hiện thời chạy trên các Goroutines.
27+
28+
> https://yourbasic.org/golang/goroutines-explained/
29+
> https://medium.com/rungo/achieving-concurrency-in-go-3f84cbf870ca
2930
3031
## 1.5.2. Tác vụ Atomic
3132

@@ -195,8 +196,9 @@ func Instance() *singleton {
195196
}
196197
```
197198

198-
* Package `sync/atomic` sẽ hỗ trợ những tác vụ atomic cho những kiểu cơ bản.
199-
* Cho việc đọc và ghi một đối tượng phức tạp, `atomic.Value` sẽ hỗ trợ hai hàm `Load``Store` để load và save dữ liệu, trả về giá trị và tham số là `interface{}` nó có thể được sử dụng trong một vài kiểu đặc biệt.
199+
Package `sync/atomic` sẽ hỗ trợ những tác vụ atomic cho những kiểu cơ bản.
200+
201+
Cho việc đọc và ghi một đối tượng phức tạp, `atomic.Value` sẽ hỗ trợ hai hàm `Load``Store` để load và save dữ liệu, trả về giá trị và tham số là `interface{}` nó có thể được sử dụng trong một vài kiểu đặc biệt.
200202

201203
```go
202204
var config atomic.Value
@@ -254,23 +256,7 @@ func main() { // Goroutine (1)
254256
}
255257
```
256258

257-
## 1.5.4 Chuỗi khởi tạo
258-
259-
* Việc khởi tạo và thực thi chương trình Go luôn luôn bắt đầu bằng hàm `main.main`.
260-
* Tuy nhiên nếu package `main` import các package khác vào, chúng sẽ được import theo thứ tự string của tên file và tên thư mục.
261-
* Nếu một package được import nhiều lần, thì những lần import sau được bỏ qua.
262-
* Nếu các package lại import các package khác nữa, chúng sẽ import vào khởi tạo các biến theo chiều sâu như hình bên dưới:
263-
264-
<div align="center" width="600">
265-
<img src="../images/ch1-12-init.ditaa.png">
266-
<br/>
267-
<span align="center"><i>Quá trình khởi tạo package</i></span>
268-
</div>
269-
<br/>
270-
271-
* Nếu hàm `init` giải phóng một Goroutine mới với từ khóa `go`, thì Goroutine và `main.main` sẽ được thực thi một cách tuần tự. Bởi vì tất cả hàm `init` và hàm `main` sẽ được hoàn thành trong cùng một thread, nó cũng sẽ thoả mãn thứ tự về mô hình nhất quán.
272-
273-
## 1.5.5 Khởi tạo một Goroutine
259+
## 1.5.4. Khởi tạo một Goroutine
274260

275261
Mệnh đề đứng sau từ khóa `go` sẽ tạo ra một Goroutine mới, ví dụ :
276262

@@ -289,9 +275,9 @@ func hello() {
289275
}
290276
```
291277

292-
## 1.5.6 Giao tiếp thông qua kênh Channel
278+
## 1.5.5. Giao tiếp thông qua kênh Channel
293279

294-
* Tác vụ gửi trên một unbufferred Channel luôn luôn xảy ra trước tác vụ nhận, dùng tính chất này cho việc đồng bộ giữa các goroutines.
280+
Tác vụ gửi trên một unbufferred Channel luôn luôn xảy ra trước tác vụ nhận, dùng tính chất này cho việc đồng bộ giữa các goroutines.
295281

296282
```go
297283
// dùng channel done để đồng bộ thứ tự thực thi
@@ -341,7 +327,7 @@ func main() {
341327

342328
Dòng `select{}` cuối cùng là một mệnh đề lựa chọn một empty channel sẽ làm cho main thread bị block, ngăn chặn chương trình kết thúc sớm. Tương tự `for{}``<- make(chan int)` nhiều hàm khác sẽ đạt được kết quả tương tự.
343329

344-
## 1.5.7 Tác vụ đồng bộ không tin cậy
330+
## 1.5.6. Tác vụ đồng bộ không tin cậy
345331

346332
Như chúng ta phân tích trước, đoạn code sau sẽ không đảm bảo thứ tự in ra kết quả bình thường. Việc chạy thực sự bên dưới sẽ có một xác suất lớn kết quả sẽ không bình thường.
347333

0 commit comments

Comments
 (0)