2013-04-02 26 views
24

Trong hướng dẫn GO, chúng tôi có trượt này:Tại sao time.sleep lại cần thiết để chạy một số goroutine?

http://tour.golang.org/#62

package main 

import (
    "fmt" 
    "time" 
) 

func say(s string) { 
    for i := 0; i < 5; i++ { 
     time.Sleep(100 * time.Millisecond) 
     fmt.Println(s) 
    } 
} 

func main() { 
    go say("world") 
    say("hello") 
} 

kết quả Chạy mã này sản xuất dự kiến ​​("thế gian" và "hello" ghi vào màn hình thay thế cho nhau 5 lần).

Tuy nhiên, nếu chúng ta nhận xét ra time.Sleep (và do đó, dòng "time" của việc nhập khẩu) và chạy lại chương trình, chúng tôi là trái với chỉ "hello" ghi vào màn hình gấp năm lần.

Điều gì là rất quan trọng về time.Sleep giúp lưu goroutine khỏi bị chết?

Trả lời

29

Nếu bạn xóa time.Sleep bạn không cung cấp cho say("world") goroutine một cơ hội để chạy. Bộ lập lịch goroutine không được ưu tiên. Các goroutine của bạn phải từ bỏ quyền kiểm soát trước khi một goroutine khác chạy. Một cách để từ bỏ quyền kiểm soát là chạy time.Sleep.

Nếu bạn đưa ra các time.Sleep từ say chức năng thì goroutine chính chạy 5 lần mà không từ bỏ quyền kiểm soát với goroutine trung học và sau đó khi trở về goroutine chính từ say chương trình thoát vì không có gì để giữ cho các chương trình sống là .

7

Vì bộ lập lịch goroutine không được ưu tiên, nên các goroutines của bạn phải từ bỏ quyền kiểm soát trước khi một goroutine khác chạy. Một cách để từ bỏ quyền kiểm soát là với time.Sleep. Một cách khác là với runtime.Gosched().

Dưới đây là hướng dẫn sửa đổi để sử dụng Gosched(): http://play.golang.org/p/jQ9mlGYXXE

Đây là một bài học hữu ích trong việc tìm hiểu goroutines. Tuy nhiên, cố gắng kiểm soát bộ lập lịch trực tiếp chắc chắn là một mẫu chống; đau buồn thường sẽ theo.

Thay vào đó, hãy suy nghĩ thêm về các goroutines như các khối giao tiếp phần cứng kỹ thuật số (các máy trạng thái là một sự tương tự tốt). Tốt hơn là bạn nên tìm hiểu về mô hình Communicating Sequential Processes trên đó goroutine dựa vào. Trong một thiết kế dựa trên CSP, mỗi goroutine có trạng thái riêng của nó và trao đổi các thông điệp để tương tác với trạng thái của các goroutine khác. Việc truyền các thông điệp buộc đồng bộ hóa, mà bộ lập lịch sử dụng để xác định hoạt động nào nhận được thời gian CPU và những gì được đặt trong hàng chờ đợi.

Khi bạn tiếp cận Đi theo cách này, bạn có thể không bao giờ phải lo lắng về lịch trình nội bộ.

+1

Kết quả tôi nhận được với 'runtime.Gosched()' hơi khác một chút. Tôi nhận được 5: hello và 4: thế giới. Trong khi với 'time.Sleep()' tôi nhận được 5 của mỗi. – Akavall

1

Nếu bạn xóa thời gian.Sleep từ chức năng nói, lệnh chính sẽ thực thi say ("hello") và chấm dứt mà không thực thi goroutine. Nếu bạn thêm thời gian. (Hoặc nếu không, hãy chọn chọn {}) trước khi kết thúc chính nó sẽ cung cấp thời gian cho goroutine chạy và chuỗi đó sẽ được chọn từ trình lên lịch.

Ví dụ:

package main 

import (
    "fmt" 
    "time" 
) 

func say(s string) { 
    for i := 0; i < 5; i++ { 
     // time.Sleep(100 * time.Millisecond) 
     fmt.Println(s) 
    } 
} 

func main() { 
    go say("world") 
    say("hello") 

    time.Sleep(1*time.Second) 
    // Vs: 
    // select {} // blocks indefinitely, requires manual interrupt 
      // In CSP-speak the empty select is like STOP. 
      // for{} would cause the cpu to max and the process's STATE will be `running` 
      // select{} will not cause the cpu to max and the process state will be `sleeping` 
} 

Đầu ra sẽ thường là 5 chào theo sau là 5 thế giới nhưng nó cũng có thể quản lý để in một trong những thế giới trước khi cuối cùng chào

TRY IT -> (http: //) goo.gl/K2v7H0