2013-08-22 59 views
9

Tôi mới tham gia chương trình Go và gặp sự cố khi hiểu được đồng thời và kênh.Đồng thời và gây nhầm lẫn kênh

package main 

import "fmt" 

func display(msg string, c chan bool){ 
    fmt.Println("display first message:", msg) 
    c <- true 
} 

func sum(c chan bool){ 
    sum := 0 
    for i:=0; i < 10000000000; i++ { 
     sum++ 
    } 
    fmt.Println(sum) 
    c <- true 
} 

func main(){ 
    c := make(chan bool) 

    go display("hello", c) 
    go sum(c) 
    <-c 
} 

Đầu ra của chương trình là:

display first message: hello 
10000000000 

Nhưng tôi nghĩ rằng nó sẽ chỉ có một dòng:

display first message: hello 

Vì vậy, trong các chức năng chính, < -c là chặn nó và chờ hai người kia đi rountines để gửi dữ liệu đến kênh. Khi chức năng chính nhận dữ liệu từ c, nó sẽ tiến hành và thoát.

hiển thị và tổng hợp chạy đồng thời và tổng mất nhiều thời gian để hiển thị nên gửi đúng với c và chương trình nên thoát trước khi tổng kết thúc ...

Tôi không chắc là tôi hiểu nó rõ ràng. Ai đó có thể giúp tôi với cái này được không? Cảm ơn bạn!

+0

Như tux21b gợi ý, có thể là do 'thời gian chạy.GOMAXPROCS'. Bump nó lên, và bạn có thể thấy một sự khác biệt. – dyoo

Trả lời

4

Đầu ra chính xác của chương trình của bạn không được xác định và phụ thuộc vào bộ lập lịch biểu. Trình lên lịch có thể chọn tự do giữa tất cả các goroutines hiện không bị chặn. Nó cố gắng để chạy những goroutine đồng thời bằng cách chuyển đổi goroutine hiện tại trong khoảng thời gian rất ngắn để người dùng nhận được cảm giác rằng mọi thứ xảy ra đồng thời. Ngoài ra, nó cũng có thể thực hiện nhiều hơn một goroutine song song trên các CPU khác nhau (nếu bạn tình cờ có một hệ thống đa lõi và tăng runtime.GOMAXPROCS). Một tình huống có thể dẫn đến đầu ra của bạn là:

  1. main tạo ra hai goroutines
  2. scheduler chọn để chuyển sang một trong những goroutines mới ngay lập tức và chọn display
  3. display in ra thông điệp và bị chặn bởi gửi kênh (c <- true) vì chưa có bộ thu.
  4. scheduler chọn để chạy sum tiếp theo
  5. tổng được tính toán và in trên màn hình
  6. scheduler lựa chọn để không tiếp tục sum goroutine (nó đã sử dụng một số tiền hợp lý của thời gian) và tiếp tục với display
  7. display gửi giá trị cho các kênh
  8. scheduler chọn để chạy chính tiếp theo
  9. bỏ chính và tất cả goroutines bị phá hủy

Nhưng đó chỉ là một lệnh thực hiện có thể. Có rất nhiều người khác và một số người trong số họ sẽ dẫn đến một đầu ra khác nhau. Nếu bạn chỉ muốn in kết quả đầu tiên và thoát khỏi chương trình sau đó, có thể bạn nên sử dụng result chan string và thay đổi chức năng main để in fmt.Println(<-result).

+0

Cảm ơn bạn đã làm rõ. Ở bước 3, hiển thị bị chặn bởi kênh gửi vì không có bộ thu. Eh ... Khi nào thì người nhận sẵn sàng? – SteelwingsJZ

+1

Kênh đồng bộ có nghĩa là cả hai, người nhận và người gửi phải sẵn sàng để truyền giá trị.Nếu goroutine thực thi 'c <- true' trước, nó sẽ bị chặn cho đến khi một goroutine khác thực thi' <-c'. Nhưng nó cũng có thể là một goroutine thực hiện '<-c' bị chặn cho đến khi có một' c <- true' khớp trong một goroutine khác. – tux21b

+0

Chỉ cần một bình luận. Theo tôi biết, bộ lập lịch Go trong phiên bản hiện tại không được ưu tiên. Khi goroutine có CPU, nó sẽ không chuyển sang một cái khác cho đến khi nó bị chặn (do I/O, kênh, mutex, v.v.). Vì vậy, nếu tổng được thực hiện đầu tiên, nó sẽ sử dụng CPU độc quyền cho đến khi bị chặn bởi kênh (Tôi không chắc chắn nếu fmt.Println có thể tạo ra một chuyển đổi CPU). Một kế hoạch preemptive được lên kế hoạch cho Go 1.2, tôi đọc. Tất nhiên, nếu GOMAXPROCS không phải là 1, goroutine khác sẽ sử dụng một quy trình SO cấp khác và sẽ được SO lên lịch biểu. Thông tin thêm tại đây: http://dominik.honnef.co/go-tip/2013-08-15/ – siritinga