Ngôn ngữ lập trình Go
Russ Cox
CNS Winter Research Review
21 tháng 1, 2010
Go
Mới
Thực nghiệm
Đồng thời
Có bộ gom rác
Ngôn ngữ
hệ thống
Hello, world
package main
import "fmt"
func main() {
fmt.Printf("Hello, 世界\n")
}
Lịch sử
Bắt đầu thiết kế vào cuối năm 2007.
Triển khai bắt đầu hoạt động vào giữa năm 2008.
Phát hành dưới dạng dự án mã nguồn mở vào tháng 11 năm 2009.
Công việc vẫn tiếp tục.
Robert Griesemer, Ken Thompson, Rob Pike, Ian Lance Taylor, Russ Cox và nhiều người khác
Mục tiêu và Động lực
Nhanh hơn!
Làm cho lập trình trở nên thú vị trở lại.
Nhắm đến phần mềm hệ thống theo nghĩa rộng.
Tại sao lập trình lại không còn thú vị?
Các ngôn ngữ biên dịch kiểu tĩnh (C, C++, Java) yêu cầu quá nhiều thao tác gõ phím và quá nhiều kiểu dữ liệu:
- dài dòng, lặp lại nhiều
- quá chú trọng vào phân cấp kiểu
- kiểu dữ liệu cản trở nhiều như giúp ích
- biên dịch mất quá nhiều thời gian
Các ngôn ngữ động (Python, JavaScript) giải quyết những vấn đề này (không cần kiểu, không cần trình biên dịch) nhưng lại đưa vào những vấn đề khác:
- lỗi xảy ra lúc chạy thay vì bị phát hiện tĩnh
- không có biên dịch nghĩa là mã chạy chậm
Liệu chúng ta có thể kết hợp điểm tốt nhất của cả hai không?
Tại sao lại cần một ngôn ngữ mới?
Không có ngôn ngữ hệ thống mới trong hơn 10 năm.
Các ngôn ngữ hiện tại được thiết kế trước khi...
... điện toán quy mô lớn, kết nối mạng và đa nhân phát triển mạnh
... phát triển phân tán quy mô Internet (nhiều thư viện) phổ biến
Go
Làm cho ngôn ngữ nhanh hơn.
Làm cho công cụ nhanh hơn.
Demo biên dịch
Build tất cả các package Go chuẩn: ~120.000 dòng mã.
Go trong một slide
Cú pháp nhẹ nhàng.
Kiểu tĩnh: đủ để biên dịch tốt, nhưng thường được suy luận.
Phương thức: trên bất kỳ kiểu nào, độc lập với hệ thống kiểu.
Kiểu trừu tượng: giá trị interface, quan hệ được suy luận tĩnh.
Phạm vi hiển thị: suy luận từ chữ hoa hay chữ thường của tên.
Hàm hạng nhất.
Thu gom rác.
Cảm giác nhẹ nhàng như ngôn ngữ kịch bản nhưng được biên dịch.
Go, đồng thời
Chi phí tạo luồng điều khiển mới (goroutine) thấp:
func main() {
go expensiveComputation(x, y, z)
anotherExpensiveComputation(a, b, c)
}
Hai phép tính nặng chạy song song.
Go, đồng thời
Chi phí tạo luồng điều khiển mới (goroutine) thấp:
for {
rw := l.Accept()
conn := newConn(rw, handler)
go conn.serve()
}
Máy chủ web đồng thời.
Kết nối mạng được ghép kênh trên epoll.
- nhiều lệnh Read bị chặn != nhiều OS thread bị chặn
Go, đồng bộ hóa
Dùng thông điệp tường minh để giao tiếp và đồng bộ hóa.
func computeAndSend(ch chan int, x, y, z int) {
ch <- expensiveComputation(x, y, z)
}
func main() {
ch := make(chan int)
go computeAndSend(ch, x, y, z)
v2 := anotherExpensiveComputation(a, b, c)
v1 := <-ch
fmt.Println(v1, v2)
}
Lưu ý việc truyền kết quả ngoài đồng bộ hóa.
Go, đồng bộ hóa
Client RPC
func (client *Client) Call(method string, args, reply interface{}) os.Error {
// Send RPC message.
call := client.Go(method, args, reply, nil)
// Read reply from Done channel.
<-call.Done
return call.Error
}
Go, đồng bộ hóa
Phân luồng client RPC
func (client *Client) input() {
for {
resp := client.readResponse()
client.mutex.Lock()
c := client.pending[resp.Seq]
client.pending[resp.Seq] = c, false
client.mutex.Unlock()
if resp.Error != "" {
c.Error = os.ErrorString(resp.error)
}
resp.Decode(c.Reply)
c.Done <- c
}
}
Go, đồng bộ hóa
Phân luồng client RPC
func (client *Client) input() {
for {
resp := client.readResponse()
client.mutex.Lock()
c := client.pending[resp.Seq]
client.pending[resp.Seq] = c, false
client.mutex.Unlock()
if resp.Error != "" {
c.Error = os.ErrorString(resp.error)
}
resp.Decode(c.Reply)
c.Done <- c
}
}
Đọc phản hồi từ mạng.
Go, đồng bộ hóa
Phân luồng client RPC
func (client *Client) input() {
for {
resp := client.readResponse()
client.mutex.Lock()
c := client.pending[resp.Seq]
client.pending[resp.Seq] = c, false
client.mutex.Unlock()
if resp.Error != "" {
c.Error = os.ErrorString(resp.error)
}
resp.Decode(c.Reply)
c.Done <- c
}
}
Tra cứu yêu cầu theo số thứ tự.
Go, đồng bộ hóa
Phân luồng client RPC
func (client *Client) input() {
for {
resp := client.readResponse()
client.mutex.Lock()
c := client.pending[resp.Seq]
client.pending[resp.Seq] = c, false
client.mutex.Unlock()
if resp.Error != "" {
c.Error = os.ErrorString(resp.error)
}
resp.Decode(c.Reply)
c.Done <- c
}
}
Giải mã các trường phản hồi từ payload.
Go, đồng bộ hóa
Phân luồng client RPC
func (client *Client) input() {
for {
resp := client.readResponse()
client.mutex.Lock()
c := client.pending[resp.Seq]
client.pending[resp.Seq] = c, false
client.mutex.Unlock()
if resp.Error != "" {
c.Error = os.ErrorString(resp.error)
}
resp.Decode(c.Reply)
c.Done <- c
}
}
Thông báo cho client rằng đã hoàn tất.
Go, đồng bộ hóa
Phân luồng client RPC
func (client *Client) input() {
for {
resp := client.readResponse()
client.mutex.Lock()
c := client.pending[resp.Seq]
client.pending[resp.Seq] = c, false
client.mutex.Unlock()
if resp.Error != "" {
c.Error = os.ErrorString(resp.error)
}
resp.Decode(c.Reply)
c.Done <- c
}
}
Có thể tạo nhiều Call với cùng kênh Done
và phân biệt cái nào đã hoàn tất bằng cách kiểm tra giá trị gửi trên kênh.
Demo goroutine
Nối 100.000 goroutine thông qua 100.001 kênh.
Gửi một giá trị vào một đầu của chuỗi.
Mỗi goroutine truyền nó tiếp, tăng lên.
Nhận giá trị ra ở đầu còn lại của chuỗi.
Trạng thái Go
Trạng thái Go
Mã nguồn mở:
- phát hành ngày 10 tháng 11 năm 2009
- các bản phát hành đều đặn (~ hàng tuần)
- toàn bộ quá trình phát triển trong kho lưu trữ Mercurial công khai
- chào đón đóng góp từ bên ngoài
- hai triển khai trình biên dịch độc lập
- XML, JSON, HTTP, TLS/SSL, RPC thuần Go, (kênh mạng,) ...
Trạng thái Go
Mã nguồn mở
Đa nền tảng:
- FreeBSD, Linux, OS X (x86, x86-64)
- (đang xử lý) Linux arm, Native Client x86, Windows x86.
Trạng thái Go
Mã nguồn mở
Đa nền tảng
Vẫn đang tiến triển, thực nghiệm. Những điều sắp tới:
- bộ gom rác cho môi trường production
- generics?
- exception?
- union hay kiểu tổng?
Câu hỏi?