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:

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:

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.

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ở:

Trạng thái Go

Mã nguồn mở

Đa nền tảng:

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:

Câu hỏi?