GoLang Interview Questions

  sonic0002        2024-05-25 03:08:18       902        0          English  简体中文  繁体中文  ภาษาไทย  Tiếng Việt 

Dưới đây là một số câu hỏi phỏng vấn GoLang thường gặp và câu trả lời tương ứng dựa trên kinh nghiệm của tác giả. Danh sách này được cập nhật thường xuyên với những hiểu biết mới. Hãy theo dõi.

Mô hình GMP của GoLang là gì?

GoLang sử dụng goroutine để đạt được tính đồng thời và nổi tiếng với khả năng hỗ trợ đồng thời cao vì ngôn ngữ này tự định nghĩa hệ thống điều phối và xử lý goroutine của riêng mình, được gọi là mô hình GMP.

Cách nó hoạt động là M thường được định nghĩa là thread của hệ điều hành được tạo ra (sau đó mỗi thread M sẽ được liên kết với một hàng đợi Process và mỗi hàng đợi Process có thể có nhiều goroutine. Số lượng hàng đợi Process được xác định bằng GOMAXPROCS(). Khi một M xử lý tất cả G từ P được liên kết của nó, nó sẽ lấy trộm G từ các M khác và cả hàng đợi P toàn cục.

Nếu một M bị treo do các khối IO hoặc các khối mạng, nó sẽ tách khỏi P của nó và P này sẽ được liên kết với một M khả dụng khác hoặc nếu nó không tồn tại, một M mới sẽ được tạo.

Nếu một goroutine không thể được đưa vào P cục bộ, nó sẽ được đưa vào hàng đợi P toàn cục. Nếu một M không thể lấy trộm G từ các M khác, nó sẽ lấy từ hàng đợi P toàn cục.

Mỗi goroutine sẽ chỉ có kích thước stack là 2K, khá nhỏ và đó là lý do tại sao GoLang hỗ trợ nhiều tính đồng thời hơn. Và loại chuyển đổi giữa việc thực thi goroutine này dựa trên không gian thread người dùng và do đó chi phí chuyển đổi ngữ cảnh không cao so với thread hoặc process

Cơ chế GC trong GoLang là gì?

Có ba giai đoạn: Mark Setup, Mark và Mark Termination. Mark Setup và Mark Terminations là STW. Giai đoạn Mark là đồng thời.

Khi thực hiện Mark Setup, Write Barrier sẽ được bật để đảm bảo tính toàn vẹn của dữ liệu và sau đó nó sẽ đợi tất cả các goroutine đang chạy dừng lại. 

Khi Marking bắt đầu, nó sẽ chiếm 25% CPU cho chính nó và có một P cho chính nó để thực hiện thu gom. Giai đoạn đánh dấu sẽ đánh dấu phần đầu vẫn đang được sử dụng, nó cố gắng xem qua stack của tất cả các goroutine và duyệt con trỏ gốc của nó và sau đó duyệt từ gốc và thực hiện đánh dấu. Trong trường hợp việc đánh dấu không thể hoàn thành kịp thời, nó sẽ thực hiện Mark Assist, có nghĩa là yêu cầu các goroutine ứng dụng khác trợ giúp. Để tăng tốc độ đánh dấu.

Khi thực hiện Mark Termination, Write Barrier sẽ tắt và việc dọn dẹp sẽ được thực hiện.

Khi nào bắt đầu thực hiện GC?

  • GC Percentage, trong đó tỷ lệ bộ nhớ mới được cấp phát so với bộ nhớ đang sử dụng trước đó trong chu kỳ GC trước đó.
  • Kích hoạt thủ công bằng cách gọi runtime.GC()

Slice hoạt động như thế nào bên dưới?

Một slice mô tả một phần của mảng và nó không giống như mảng.

Tiêu đề Slice có độ dài, dung lượng và cả con trỏ phần tử thứ không. Bên dưới nó được hỗ trợ bởi một mảng. Nếu đạt đến dung lượng, không thể phát triển nữa, cần phải tạo lại mảng bên dưới và cấp phát lại. Nếu không đạt đến dung lượng, sẽ có thể phát triển khi cần.

Panic, defer và recover

Đối với defer, nó hoạt động như FILO

  1. Các đối số của một hàm được hoãn lại được đánh giá khi câu lệnh defer được đánh giá.

  2. Các lệnh gọi hàm được hoãn lại được thực thi theo thứ tự Last In First Out sau khi hàm bao quanh trả về

  3. Các hàm được hoãn lại có thể đọc và gán cho các giá trị trả về được đặt tên của hàm trả về.

Panic sẽ trả về việc thực thi và các defer trong hàm sẽ tiếp tục. 

Recover chỉ hữu ích bên trong các hàm được hoãn lại. Trong hàm bình thường, recover không có tác dụng và không làm gì cả.

Defer recover chỉ hoạt động cho goroutine hiện tại, nó sẽ không hoạt động cho goroutine được tạo ra của nó.

Context, nó rất mạnh mẽ

4 hàm trong interface Context: 

  • Deadline(),
  • Done(),
  • Err(),
  • Value(key interface{})

Lợi ích cho điều này là chia sẻ tài nguyên, kiểm soát goroutine

Có các goroutine dẫn xuất như WithCancel, WithDeadline, WithTimeout, WithValue

WithCancel: 

  1. Hàm Cancel sẽ được chuyển xuống các ngữ cảnh con

  2. Khi một ngữ cảnh con mới được tạo, nó sẽ được đăng ký với ngữ cảnh cha. 

WithValue

  1. Khóa phải có thể so sánh được vì có một kiểm tra c.key == key khi gọi hàm Value()

  2. Slice, map và function không thể so sánh được. Chủ yếu là vì slice không thể so sánh được vì nó là một kiểu tham chiếu, nơi chỉ so sánh địa chỉ là vô nghĩa và độ phức tạp cũng tăng lên khi so sánh nội dung trong slice do tính năng len/cap

Channel

Channel là một cách để chia sẻ bộ nhớ bằng giao tiếp

Có channel có bộ đệm và không có bộ đệm

  • Đóng channel nil hoặc đã đóng sẽ gây ra panic
  • Gửi giá trị đến channel nil sẽ chặn mãi mãi, channel đã đóng sẽ gây ra panic
  • Nhận dữ liệu từ channel nil sẽ chặn mãi mãi, channel đã đóng sẽ trả về ngay lập tức

Khi nào rò rỉ goroutine sẽ xảy ra?

Một số trường hợp bao gồm:

  1. Khi channel không được đóng trong khi một goroutine tiếp tục chờ nhận dữ liệu từ channel
  2. Khi một số tài nguyên không được đóng đúng cách trong khi một số goroutine vẫn đang chờ phản hồi từ phía bên kia và không có thời gian chờ thích hợp nào được đặt cho IO chặn

Sự khác biệt giữa new() và make() là gì?

new() sẽ chỉ cấp phát bộ nhớ trong khi make() sẽ khởi tạo dữ liệu

Đối tượng được tạo bằng new() đã sẵn sàng để sử dụng nhưng cần phải khởi tạo rõ ràng các thuộc tính của nó trước khi có thể sử dụng khi cần

make() chỉ có thể được sử dụng trên các kiểu slice, map và channel.

Sự khác biệt chi tiết có thể được tìm thấy ở đây.

Sự khác biệt giữa con trỏ và receiver phương thức không phải con trỏ?

Nó giống như truyền theo tham chiếu so với truyền theo giá trị trong các lệnh gọi hàm.

Nếu struct sẽ bị thay đổi hoặc struct quá lớn đối với receiver, người ta sẽ chọn xác định receiver phương thức con trỏ.

Nếu một số hàm có receiver con trỏ, thì các hàm còn lại cũng nên có để giữ tính nhất quán.

Làm thế nào để kiểm tra xem một struct có triển khai một interface hay không?

Không có từ khóa implements trong GoLang như các ngôn ngữ khác như Java. Nếu một struct triển khai tất cả các phương thức của một interface, nó được coi là triển khai interface đó. Nếu mã struct không ở cùng một nơi với định nghĩa interface, có thể khó tìm ra liệu một struct có triển khai một interface cụ thể hay không. Điều này có thể gây ra sự cố thời gian chạy trong một số trường hợp.

Có một vài cách để kiểm tra điều đó:

  • Type assertion với đối tượng giả. var _ = (SomeStruct{}).(SomeInterface)
  • Sử dụng reflection. reflect.TypeOf(OneInterface).Implements(reflect.TypeOf(SomeInterface).Elem())

Đối với các phương pháp khác, có thể tìm thấy ở đây.

MEMORY  CONCURRENCY  INTERVIEW QUESTION  GOLANG 

           

  RELATED


  0 COMMENT


No comment for this article.



  RANDOM FUN

Huawei 3-fold Phone vs iPhone 3-fold Phone