2016-01-20 15 views
8

Tại sao lại hoảng sợ khi ghi vào kênh đã đóng?Tại sao lại hoảng sợ khi viết thư cho một kênh đã đóng?

Trong khi người ta có thể sử dụng value, ok := <-channel thành ngữ để đọc từ các kênh, và do đó kết quả ok có thể được kiểm tra đánh một kênh đóng:

// reading from closed channel 

package main 

import "fmt" 

func main() { 
    ch := make(chan int, 1) 
    ch <- 2 
    close(ch) 

    read(ch) 
    read(ch) 
    read(ch) 
} 

func read(ch <-chan int) { 
    i,ok := <- ch 
    if !ok { 
     fmt.Printf("channel is closed\n") 
     return 
    } 
    fmt.Printf("read %d from channel\n", i) 
} 

Output:

read 2 from channel 
channel is closed 
channel is closed 

Run "đọc từ kênh đã đóng "trên Playground

Việc ghi vào kênh có thể bị đóng là phức tạp hơn, vì Go sẽ hoảng sợ nếu bạn chỉ cố gắng wri te khi kênh được đóng lại:

//writing to closed channel 

package main 

import (
    "fmt" 
) 

func main() { 
    output := make(chan int, 1) // create channel 
    write(output, 2) 
    close(output) // close channel 
    write(output, 3) 
    write(output, 4) 
} 

// how to write on possibly closed channel 
func write(out chan int, i int) (err error) { 

    defer func() { 
     // recover from panic caused by writing to a closed channel 
     if r := recover(); r != nil { 
      err = fmt.Errorf("%v", r) 
      fmt.Printf("write: error writing %d on channel: %v\n", i, err) 
      return 
     } 

     fmt.Printf("write: wrote %d on channel\n", i) 
    }() 

    out <- i // write on possibly closed channel 

    return err 
} 

Output:

write: wrote 2 on channel 
write: error writing 3 on channel: send on closed channel 
write: error writing 4 on channel: send on closed channel 

Run "bằng văn bản cho kênh kín" trên Playground

Theo như tôi biết, có không phải là một thành ngữ đơn giản để viết vào một kênh có thể đóng mà không cần phải hoảng sợ. Tại sao không? Lý do đằng sau hành vi bất đối xứng như thế nào giữa đọc và viết?

+3

Làm sao chúng ta biết được? Hỏi về nhóm google golang, có thể một trong các tác giả sẽ trả lời bạn. Tôi có thể nghĩ ra một lý do. Nó chỉ là một thiết kế tốt để đóng một kênh ở phía nhà sản xuất. Panicking buộc bạn phải thiết kế ứng dụng của bạn theo cách như vậy. – creker

+5

Đóng kênh là tín hiệu cho thấy ở đây sẽ không còn giá trị nào nữa. Việc ghi vào một kênh đã đóng là lỗi chương trình, điều này gây hoảng loạn. – JimB

Trả lời

11

Từ Go Language Spec:

Đối với một kênh c, được xây dựng trong chức năng close (c) ghi rằng không giá trị này sẽ được gửi trên kênh. Đó là lỗi nếu c là một kênh chỉ nhận . Việc gửi hoặc đóng kênh đã đóng gây ra hiện tượng hoảng loạn thời gian chạy là . Đóng kênh nil cũng gây ra một hoảng sợ thời gian chạy. Sau khi gọi gần, và sau khi bất kỳ giá trị đã gửi trước đó đã được nhận được, các hoạt động nhận sẽ trả lại giá trị bằng không cho loại kênh mà không bị chặn. Hoạt động nhận nhiều giá trị trả về giá trị đã nhận cùng với dấu hiệu cho biết kênh có bị đóng hay không.

Nếu bạn viết thư cho kênh đã đóng, chương trình của bạn sẽ hoảng loạn. Bạn có thể có khả năng catch this error with recover nếu bạn thực sự muốn làm điều đó, nhưng trong một tình huống mà bạn không biết liệu kênh bạn đang viết có mở hay không thường là dấu hiệu của một lỗi trong chương trình.

Một số trích dẫn:

Đây là một động lực:

Một kênh "gần" thực sự chỉ là một gửi của một giá trị đặc biệt trên một kênh . Đây là một giá trị đặc biệt hứa hẹn sẽ không có thêm giá trị nào được gửi . Cố gắng gửi một giá trị trên một kênh sau khi đã bị đóng cửa sẽ bị hoảng sợ, vì thực sự việc gửi giá trị sẽ vi phạm bảo đảm được cung cấp gần. Kể từ khi đóng chỉ là một loại đặc biệt của gửi, nó cũng không được phép sau khi kênh đã được đóng lại.

Dưới đây là một:

Việc sử dụng duy nhất của kênh gần là để báo hiệu cho người đọc rằng có không có nhiều giá trị sắp tới. Điều đó chỉ có ý nghĩa khi có một nguồn giá trị đơn lẻ hoặc khi nhiều nguồn phối hợp. Có không có chương trình hợp lý trong đó nhiều goroutines đóng một kênh mà không cần liên lạc. Điều đó có nghĩa là nhiều goroutines sẽ biết rằng không còn giá trị nào để gửi - cách chúng có thể xác định rằng nếu chúng không giao tiếp?

(Ian Lance Taylor)

-

Dưới đây là một:

bế một kênh phát hành nó như là một nguồn tài nguyên. Nó không có ý nghĩa hơn để đóng một kênh nhiều lần thay vì đóng một tệp mô tả nhiều lần, hoặc giải phóng một khối bộ nhớ được phân bổ nhiều lần. Các hành động như vậy ngụ ý mã bị hỏng, đó là lý do tại sao đóng kênh đóng lại gây ra sự hoảng sợ.

(Rob Pike)

-

Nguồn: Go design detail rationale question - channel close

Các vấn đề liên quan