Why Does My Go Timeout Not Work in this Channel Example?

DDD
Release: 2024-11-08 17:48:02
Original
685 people have browsed it

Why Does My Go Timeout Not Work in this Channel Example?

Go: Using Timeouts with Channels

In Go, timeouts and channels provide a convenient way to control the execution of goroutines and synchronize their results. However, there are certain scenarios where the timeout case may not execute as expected.

Problem Statement

Consider the following Go code:

import "fmt"
import "time"

func check(u string) bool {
    time.Sleep(4 * time.Second)
    return true
}

func IsReachable(urls []string) bool {

    ch := make(chan bool, 1)
    for _, url := range urls {
        go func(u string) {
            select {
            case ch <- check(u):
            case <-time.After(time.Second):
                ch <- false
            }
        }(url)
    }
    return <-ch
}
func main() {
    fmt.Println(IsReachable([]string{"url1"}))
}
Copy after login

The goal of this code is to check if all URLs in the provided list are reachable. If any URL fails to respond within a second, the function should return false.

However, when executing this code, it will always return true. The timeout case is not getting executed.

Explanation

The issue arises due to the way check(u) is being executed. In the IsReachable function, each goroutine checks the reachability of a URL by calling check(u). However, check(u) sleeps for 4 seconds in the current goroutine before returning.

Within the select statement, the case ch <- check(u): branch is the first to become available, as check(u) has already returned. This prevents the timeout case from ever executing, resulting in the function always returning true.

Solution

To resolve this issue, the check(u) function should be executed in a separate goroutine. This allows the select statement to properly handle the timeout case.

Here's the updated code:

import "fmt"
import "time"

func check(u string, checked chan<- bool) {
    time.Sleep(4 * time.Second)
    checked <- true
}

func IsReachable(urls []string) bool {

    ch := make(chan bool, 1)
    for _, url := range urls {
        go func(u string) {
            checked := make(chan bool)
            go check(u, checked)
            select {
            case ret := <-checked:
                ch <- ret
            case <-time.After(1 * time.Second):
                ch <- false
            }
        }(url)
    }
    return <-ch
}
func main() {
    fmt.Println(IsReachable([]string{"url1"}))
}
Copy after login

Now, if any of the URLs fail to respond within a second, the function will return false. Additionally, if only one URL is available, the function will return true.

The above is the detailed content of Why Does My Go Timeout Not Work in this Channel Example?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!