Pratik
Pratik

Reputation: 1399

Non-blocking channel in go

I have some code like this:

go func(ch chan bool) chan bool {

    // some processing
    ch <- true
    return ch
}(ch)

for i := 0; i < TotalQuestions; i++ {
    // check if channel ch has some value
    // If it has then execute below statements, else break out of the loop


    fmt.Println(questions[i])
    answer, _ := InputReader.ReadString('\n')

    // some processing

}
fmt.Println("Your Total score is " + strconv.Itoa(TotalScore) + " out of " + strconv.Itoa(TotalQuestions))

Now what I want to do is to check if channel ch has a value (in for loop). If it has a value then I want to break out of the for loop to print the last statement. otherwise, I want to continue my loop. I tried to insert select block but that didn't work (The channel got blocked and code didn't print questions). How to do that?

Upvotes: 2

Views: 9326

Answers (2)

pPanda_beta
pPanda_beta

Reputation: 648

Functional way of reading from a channel in a non-blocking manner:

func CollectChanOne[T any](ch <-chan T) (T, bool) {
    select {
    case val, stillOpen := <-ch:
        return val, stillOpen
    default:
        var zeroT T
        return zeroT, false
    }
}

Example: https://go.dev/play/p/Njwyt32B4oT

N.B. This example also have another method CollectChanRemaining() which reads all buffered elements in the channel.

Upvotes: 1

nilsocket
nilsocket

Reputation: 1571

package main
    
import (
    "fmt"
    "log"
    "math/rand"
    "time"
)

func main() {

    // user score, no.of questions asked so far
    var score, num int
    var correct bool // temporary variable to decide if the answer is right
    // questions
    var questions = make([]string, 13)

    t1 := time.Tick(time.Second * 7) // timer loop:
    for {
        select {
        case <-t1:
            log.Println("ran out of time")
            break loop
        default:
            // have any questions further questions to ask
            if num < len(questions) {

                // simulate typing
                time.Sleep(time.Millisecond * 777)

                // correct or wrong answer
                correct = (rand.Intn(777)%2 == 0)

                if correct {
                    fmt.Println("you did it")
                    score++ //increase score
                } else {
                    fmt.Println("try again")
                }

            } else {
                // no questions, state and break
                log.Println("all questions were finished")
                break loop //break loop, all questions were finished
            }
            num++
        }
    }

    //print final score
    fmt.Println("your score is:", score)
}

Upvotes: 5

Related Questions