Отправка значения в канал не готова в выбранном - PullRequest
0 голосов
/ 03 мая 2020
package main

import (
    "fmt"
    "time"
)

func main() {

    ch := make(chan int)
    go func() {
        fmt.Printf("func at %d\n", time.Now().UnixNano())
        select {
        case ch <- 1:
            fmt.Println("running send")
        default:
            fmt.Println("running default")
        }
    }()

    time.Sleep(100 * time.Millisecond)
    fmt.Printf("main at %d\n", time.Now().UnixNano())
    fmt.Println(<-ch)
}

игровая площадка здесь

Я исследовал один день, но все еще не могу объяснить, почему case ch <- 1: не готов, и выбран вариант по умолчанию для запуска. Конечно, это вызывает тупик!

Ответы [ 2 ]

1 голос
/ 03 мая 2020

С do c:

Если канал не буферизован, отправитель блокируется, пока получатель не получит значение. Если у канала есть буфер, отправитель блокируется только до тех пор, пока значение не будет скопировано в буфер; если буфер заполнен, это означает ожидание, пока какой-либо получатель не получит значение.

Один из способов - использовать это. Вот и получатель goroutine создается первым. Кроме того, если приемник еще не готов, будет выбран регистр по умолчанию. И если он будет готов, указанный случай c будет готов. Если вы запустите это несколько раз, вы увидите, что происходит один из следующих случаев.

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    // goroutine acts as the reciever
    go func() {
        fmt.Printf("main at %d\n", time.Now().UnixNano())
        fmt.Println(<-ch)
    }()
    go func() {
        fmt.Printf("func at %d\n", time.Now().UnixNano())
        select {
        case ch <- 1:
            fmt.Println("running send")
        default:
            fmt.Println("running default")
        }
    }()
    time.Sleep(1 * time.Second) // Wait for the goroutines
}

Другое решение будет использовать буферизованный канал:

package main

import (
    "fmt"
    "time"
)

func main() {

    ch := make(chan int, 1)
    go func() {
        fmt.Printf("func at %d\n", time.Now().UnixNano())
        select {
        case ch <- 1:
            fmt.Println("running send")
        default:
            fmt.Println("running default")
        }
    }()

    time.Sleep(100 * time.Millisecond)
    fmt.Printf("main at %d\n", time.Now().UnixNano())
    fmt.Println(<-ch)
}

Также прочитайте это thread on stackoverflow

0 голосов
/ 03 мая 2020

Вы создали канал Go с make (chan int), который не буферизуется. Вам нужен буферизованный канал (который не обязательно блокируется), вы должны использовать make (chan int, 20), где 20 - это размер канала

. В небуферизованных каналах важно то, что они также являются синхронными, поэтому они всегда блокируют как запись, так и чтение. То же самое может случиться с буферизованными каналами, когда буфер заполняется.

Попробуйте код ниже

package main

import (
    "fmt"
    "time"
)

func main() {

    ch := make(chan int, 20)
    go func() {
        fmt.Printf("func at %d\n", time.Now().UnixNano())
        select {
        case ch <- 1:
            fmt.Println("running send")
        default:
            fmt.Println("running default")
        }
    }()

    time.Sleep(100 * time.Millisecond)
    fmt.Printf("main at %d\n", time.Now().UnixNano())
    fmt.Println(<-ch)
}
...