2014-07-23 33 views
6

Tôi đang cố gắng hiểu, cách thức hoạt động của kênh golang. Tôi đọc một cuốn sách về ngôn ngữ đi và tìm thấy ví dụ sau.Tại sao xảy ra ở đây một bế tắc

package main 

import (
    "fmt" 
) 

// Send the sequence 2, 3, 4, ... to returned channel 
func generate() chan int { 
    ch := make(chan int) 
    go func() { 
     for i := 2; i <= 100 ; i++ { 
      ch <- i 
     } 
    }() 
    return ch 
} 

// Filter out input values divisible by 'prime', send rest to returned channel 
func filter(in chan int, prime int) chan int { 
    out := make(chan int) 
    go func() { 
     for { 
      if i := <-in; i%prime != 0 { 
       out <- i 
      } 
     } 
    }() 
    return out 
} 

func sieve() chan int { 
    out := make(chan int) 
    go func() { 
     ch := generate() 
     for { 
      prime := <-ch 
      ch = filter(ch, prime) 
      out <- prime 
     } 
    }() 
    return out 
} 

func main() { 
    primes := sieve() 
    for { 
     fmt.Println(<-primes) 
    } 
} 

Khi tôi chạy programm này, tôi đã có một bế tắc, nhưng khi tôi thay đổi tạo ra chức năng để

// Send the sequence 2, 3, 4, ... to returned channel 
func generate() chan int { 
    ch := make(chan int) 
    go func() { 
     for i := 2; ; i++ { 
      ch <- i 
     } 
    }() 
    return ch 
} 

Sau đó programm sẽ chạy vòng lặp vô hạn, nhưng không phải bế tắc. Tại sao tôi bị bế tắc, khi tôi loại bỏ tình trạng trong vòng lặp?

Trả lời

9

Bạn có ý nghĩa gì với nguyên tắc chặn?

Bạn có thể nhìn thấy nó được minh họa trong bài đăng blog "The Nature Of Channels In Go"

cho một kênh unbuffered:

http://3.bp.blogspot.com/-vnJIWvlbP-E/UwDVICJKB9I/AAAAAAAANX0/T04V_58i8Vs/s1600/Screen+Shot+2014-02-16+at+10.10.54+AM.png

(Minh họa từ bài đăng blog "The Nature Of Channels In Go", được viết bởi William Kennedy, thg 2 năm 2014)

Các kênh không bị chặn không có dung lượng và do đó yêu cầu cả hai goroutines sẵn sàng thực hiện bất kỳ trao đổi nào.
Khi goroutine cố gắng ghi tài nguyên vào kênh không bị chặn và không có goroutine nào chờ để nhận tài nguyên, kênh sẽ khóa goroutine và chờ nó.
Khi một goroutine cố gắng đọc từ một kênh không bị chặn, và không có goroutine chờ đợi để gửi một tài nguyên, kênh sẽ khóa goroutine và làm cho nó chờ đợi.

Đó là những gì xảy ra trong trường hợp của bạn với người đọc:

func main() { 
    primes := sieve() 
    for { 
     fmt.Println(<-primes) 
    } 
} 

từ primes không bao giờ đóng cửa, main vẫn bị chặn.
Nó (main) là ở bước 3:

ở bước 3, goroutine bên phải đặt tay vào kênh hoặc thực hiện một đọc.
Goroutine đó cũng bị khóa trong kênh cho đến khi quá trình trao đổi hoàn tất.

Người gửi không bao giờ gọi close(primes).

+0

Tôi đã bế tắc, bởi vì goroutine trong chức năng tạo ra là các kênh được đóng sau 100 vòng và số nguyên tố vẫn chờ đợi để nhận dữ liệu phải không? –

+0

@zero_coding không được đóng: Tôi không thấy 'close (số nguyên tố)' ở bất cứ đâu – VonC

+0

Ý tôi là vì người nhận không đóng, nhưng người gửi gần đúng? Không có người gửi nữa. –

5

Hãy xem xét một ví dụ đơn giản:

func generate() chan int { 
    ch := make(chan int) 
    go func() { 
     for i := 2; /*i < 100*/; i++ { 
      ch <- i 
     } 
    }() 
    return ch 
} 

func main() { 
    for i := range generate() { 
     fmt.Println(i) 
    } 
} 

Với điều kiện i < 100 không chú thích, các goroutine sinh ra bởi generate dừng sau khi gửi 98 con số. Tuy nhiên, nó không đóng kênh, do đó, main không có cách nào để biết rằng sẽ không còn số nào được gửi và kênh đó chỉ tiếp tục chặn trên kênh. Kể từ main bây giờ là goroutine duy nhất vẫn còn tồn tại (một trong những khác đã trở lại), và nó chặn, bạn có một bế tắc.

+0

Tôi cũng đã đọc chủ đề về chặn kênh nhưng tôi không hiểu, điều đó có ý nghĩa gì với việc chặn kênh. Kênh bao gồm người gửi và người nhận. Người gửi có thể gửi một cái gì đó chỉ cùng một lúc tại thời điểm đó, điều đó có nghĩa là người nhận phải nhận được gói, cho đến khi nó có thể tiếp tục công việc của mình. Bạn có ý nghĩa gì với việc chặn nguyên tắc? –

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