Closed tpphu closed 5 years ago
Phú đã kiểm chứng và thấy cách chúng ta hiểu về channel cũng capacity/buffer của nó vẫn còn đúng. Tuy nhiên do cách chúng ta in ra màn hình dòng Println trước hành động push vào channel nên nó như vậy thôi.
Phú sẽ giải thích trong buổi học buổi tối cho các bạn.
Các bạn chạy câu lệnh để limit CPU để thấy thêm chi tiết.
$ GOMAXPROCS=1 go run main.go
Bạn sẽ thấy output có thứ tự và dễ hiểu như sau:
[GEN] channel: 2
[GEN] channel: 3
[GEN] channel: 4
[GEN] channel: 5
[SQ] channel: 4
[OUT]: 4
[SQ] channel: 9
[OUT]: 9
[SQ] channel: 16
[OUT]: 16
[SQ] channel: 25
[OUT]: 25
Bạn sẽ thấy các giá trị in ra hơi lộn xộn, tuy nhiên nó vẫn đúng, và bạn cần phải suy nghĩ tại sao nó như vậy
$ GOMAXPROCS=4 go run main.go
[SQ] channel: 4
[GEN] channel: 2
[GEN] channel: 3
[GEN] channel: 4
[GEN] channel: 5
[OUT]: 4
[SQ] channel: 9
[OUT]: 9
[SQ] channel: 16
[OUT]: 16
[SQ] channel: 25
[OUT]: 25
ubuntu@ubuntu:~/go/src/golang-trainning/gorountine-pipline$ GOMAXPROCS=1 go run main.go GEN 2 GEN 3 SQ 4 GEN 4 OUT 4 SQ 9 GEN 5 OUT 9 SQ 16 OUT 16 SQ 25 OUT 25 ubuntu@ubuntu:~/go/src/golang-trainning/gorountine-pipline$ GOMAXPROCS=4 go run main.go GEN 2 GEN 3 SQ 4 GEN 4 OUT 4 SQ 9 GEN 5 OUT 9 SQ 16 OUT 16 SQ 25 OUT 25
em thấy nó cũng vậy. Máy của em là VMware ubuntu 4 core.
Em có một giả thuyết thế này: không bao quan trọng là bao nhiêu cpu. mà quan trọng là cơ chế khóa channel phải đảm bảo lúc nào trong channel cũng có một đơn vị. Còn vấn đề nó xuất cái gì trước sau đó là do các thread hoàn thành nhanh hay chậm
Anh sẽ kiểm tra lại, trên ubuntu, nhưng về lý thuyết chạy 1CPU phải khác với 4CPU không thể cùng kết quả được.
Mình sẽ có cần chữ này đằng trước Ubuntu:
$ env GOMAXPROCS=4 go run main.go
$ env GOMAXPROCS=1 go run main.go
Em thử lại xem nha.
Nếu chạy 1CPU và 4CPU mà bằng nhau, thì những gì chúng ta nghĩ về ngôn ngữ lập trình chỗ này sẽ có gì đó không đúng.
Đây là một ví dụ chạy thực tế:
https://play.golang.org/p/ZSBitGdqcSo
Do vậy em có thể copy và chạy thử cái này:
package main
import (
"fmt"
"runtime"
"time"
)
// https://gobyexample.com/channel-buffering
// Nhan vao mot danh sach cac so nguyen
// Tra ra mot channel
func gen(nums ...int) <-chan int {
// Run Step 1
// Bufferred Channel
out := make(chan int, 4) //capacity
// Run Step 2
go func() {
for _, n := range nums {
// Chi day dc vao channel khi ma len < capacity
out <- n
// In ra o day co nghia la da push dc
fmt.Printf("\n[GEN] channel: %d", n)
}
close(out)
}()
// Run Step
return out
}
func sq(in <-chan int) <-chan int {
// Unbufferred Channel
out := make(chan int)
go func() {
for n := range in {
out <- n * n
fmt.Printf("\n[SQ] channel: %d", n*n)
}
close(out)
}()
return out
}
func main() {
fmt.Println("Num CPUs:", runtime.NumCPU())
runtime.GOMAXPROCS(1)
// Set up the pipeline.
c := gen(2, 3, 4, 5)
out := sq(c)
// Consume the output.
go func() {
// Vi out la Unbufferred Channel
// nen khi sleep, thi func sq khong the push them dc value vao sq channel
// do vay ban se khong thay dong in ra
for v := range out {
time.Sleep(1 * time.Second)
fmt.Printf("\n[OUT]: %d", v)
}
}()
time.Sleep(30 * time.Second)
}
Ví dụ này thấy trên lớp nó không chạy đúng như dự định ban đầu, channel ngay lập tức có thể đẩy vào được 2 giá trị.