search
HomeBackend DevelopmentGolangGo program exits before goroutine work completes

Go program exits before goroutine work completes

Feb 08, 2024 pm 10:57 PM
go language

Go 程序在 goroutine 工作完成之前退出

In this article, php editor Xiaoxin will introduce an important issue about Go programs: the situation of exiting before the goroutine work is completed. In the Go language, goroutine is a lightweight thread that can execute tasks concurrently. However, when our program may exit before the goroutine work is completed, we need to understand how to handle this situation to ensure that our program completes the task correctly. In the following content, we will explore this problem and provide some solutions to solve it.

Question Content

I'm having trouble understanding how to properly block and close channels. I'm starting an arbitrary number of workers and I'm finding that my main function either exits before the workers complete or hangs due to unclosed channels. I need a better way to stop the worker from reading the channel without exiting the main channel, and then gracefully close the channel when finished to end the loop. Any attempts I make end in deadlock.

I tried a few things including using a wait group, but the problem persists. I noticed that by adding time.sleep the program works as expected, but commenting it out results in no work being done.

time.sleep(time.duration(10 * time.second))

This is a runnable example https://go.dev/play/p/qhqnj-ajqbi which preserves sleep. This is the broken code with the sleep timeout commented out.

package main

import (
    "fmt"
    "sync"
    "time"
)

// some complicated work
func do(num int, ch chan<- int) {
    time.sleep(time.duration(500 * time.millisecond))
    ch <- num
}

func main() {

    results := make(chan int)

    // for some number of required complicated work
    for i := 0; i < 53; i++ {
        go do(i, results)
    }

    var wg sync.waitgroup

    // start 3 workers which can process results
    for i := 0; i < 3; i++ {
        wg.add(1)
        go func(id int) {
            defer wg.done()
            worker(id, results)
        }(i)
    }

    // handle closing the channel when all workers complete
    go func() {
        wg.wait()
        close(results)
    }()

    //time.sleep(time.duration(10 * time.second))

    fmt.println("donezo")
}

// process the results of do() in a meaningful way
func worker(id int, ch <-chan int) {
    fmt.println("starting worker", id)

    for i := range ch {
        fmt.println("channel val:", i)
    }
}

I also tried moving defer wg.done() inside the worker() func but it's the same problem and doesn't work without sleep.

// process the results of do() in a meaningful way
func worker(wg *sync.WaitGroup, id int, ch <-chan int) {
    fmt.Println("starting worker", id)

    defer wg.Done()

    for i := range ch {
        fmt.Println("channel val:", i)
    }
}

Did I choose the wrong paradigm, or am I just using the wrong paradigm?

Workaround

I originally asked "Can I make some small adjustments to my code to make it work? Or do I have to rethink this problem?" I The answer found is that, yes, there is a small adjustment.

I had to learn an interesting basic concept about channels: you can read data from a closed channel, i.e. drain the channel. As mentioned in my original example range never terminates because I can't find a good place to close the channel, and even when I force it in other creative ways the program behaves poorly Behavior

  • Exited without processing all content in the channel
  • Deadlock or sending on closed channel

This is due to a subtle difference in the "real" code where the time required to process the channel contents is longer than the time required to populate the channel and Things are out of sync.

Since there is no clear practical way to close the channel in my sender (which is recommended in 99% of channel tutorials), when you have multiple workers reading the channel and the workers don't know about it, by It's actually acceptable to do this with a goroutine in main where the last value is read.

solution

I wrapped the worker in its own sync.waitgroup and used worker.wait() to block the program exit, thus allowing the work to "finish". When there is no more data to send, I close() the channel independently, i.e. I block by waiting for the writer to finish using their own wait group. close Provides a termination case for range loops because when the channel's default value is returned, i.e. the eof type is reached when the end of the channel is reached, it will end. A blocking rendezvous channel has no endpoint until it is closed.

My take on this is that if you don't know how many values ​​will be pushed in parallel, go has no way of knowing the length of the unbuffered channel because it's in scope, until you close it. . Since it's closed, it means reading whatever is left until the termination value or the end. workers.wait() will block until completed.

Examples of resolved operations https://www.php.cn/link/2bf0ccdbb4d3ebbcb990af74bd78c658

Example of reading closed channel https://www.php.cn/link/d5397f1497b5cdaad7253fdc92db610b

Output

filling 0
filling 1
filling 2
filling 3
filling 4
filling 5
filling 6
filling 7
filling 8
filling 9
closed
empyting 0
empyting 1
empyting 2
empyting 3
empyting 4
empyting 5
empyting 6
empyting 7
empyting 8
empyting 9

The above is the detailed content of Go program exits before goroutine work completes. For more information, please follow other related articles on the PHP Chinese website!

Statement
This article is reproduced at:stackoverflow. If there is any infringement, please contact admin@php.cn delete
String Manipulation in Go: Mastering the 'strings' PackageString Manipulation in Go: Mastering the 'strings' PackageMay 14, 2025 am 12:19 AM

Mastering the strings package in Go language can improve text processing capabilities and development efficiency. 1) Use the Contains function to check substrings, 2) Use the Index function to find the substring position, 3) Join function efficiently splice string slices, 4) Replace function to replace substrings. Be careful to avoid common errors, such as not checking for empty strings and large string operation performance issues.

Go 'strings' package tips and tricksGo 'strings' package tips and tricksMay 14, 2025 am 12:18 AM

You should care about the strings package in Go because it simplifies string manipulation and makes the code clearer and more efficient. 1) Use strings.Join to efficiently splice strings; 2) Use strings.Fields to divide strings by blank characters; 3) Find substring positions through strings.Index and strings.LastIndex; 4) Use strings.ReplaceAll to replace strings; 5) Use strings.Builder to efficiently splice strings; 6) Always verify input to avoid unexpected results.

'strings' Package in Go: Your Go-To for String Operations'strings' Package in Go: Your Go-To for String OperationsMay 14, 2025 am 12:17 AM

ThestringspackageinGoisessentialforefficientstringmanipulation.1)Itofferssimpleyetpowerfulfunctionsfortaskslikecheckingsubstringsandjoiningstrings.2)IthandlesUnicodewell,withfunctionslikestrings.Fieldsforwhitespace-separatedvalues.3)Forperformance,st

Go bytes package vs strings package: Which should I use?Go bytes package vs strings package: Which should I use?May 14, 2025 am 12:12 AM

WhendecidingbetweenGo'sbytespackageandstringspackage,usebytes.Bufferforbinarydataandstrings.Builderforstringoperations.1)Usebytes.Bufferforworkingwithbyteslices,binarydata,appendingdifferentdatatypes,andwritingtoio.Writer.2)Usestrings.Builderforstrin

How to use the 'strings' package to manipulate strings in Go step by stepHow to use the 'strings' package to manipulate strings in Go step by stepMay 13, 2025 am 12:12 AM

Go's strings package provides a variety of string manipulation functions. 1) Use strings.Contains to check substrings. 2) Use strings.Split to split the string into substring slices. 3) Merge strings through strings.Join. 4) Use strings.TrimSpace or strings.Trim to remove blanks or specified characters at the beginning and end of a string. 5) Replace all specified substrings with strings.ReplaceAll. 6) Use strings.HasPrefix or strings.HasSuffix to check the prefix or suffix of the string.

Go strings package: how to improve my code?Go strings package: how to improve my code?May 13, 2025 am 12:10 AM

Using the Go language strings package can improve code quality. 1) Use strings.Join() to elegantly connect string arrays to avoid performance overhead. 2) Combine strings.Split() and strings.Contains() to process text and pay attention to case sensitivity issues. 3) Avoid abuse of strings.Replace() and consider using regular expressions for a large number of substitutions. 4) Use strings.Builder to improve the performance of frequently splicing strings.

What are the most useful functions in the GO bytes package?What are the most useful functions in the GO bytes package?May 13, 2025 am 12:09 AM

Go's bytes package provides a variety of practical functions to handle byte slicing. 1.bytes.Contains is used to check whether the byte slice contains a specific sequence. 2.bytes.Split is used to split byte slices into smallerpieces. 3.bytes.Join is used to concatenate multiple byte slices into one. 4.bytes.TrimSpace is used to remove the front and back blanks of byte slices. 5.bytes.Equal is used to compare whether two byte slices are equal. 6.bytes.Index is used to find the starting index of sub-slices in largerslices.

Mastering Binary Data Handling with Go's 'encoding/binary' Package: A Comprehensive GuideMastering Binary Data Handling with Go's 'encoding/binary' Package: A Comprehensive GuideMay 13, 2025 am 12:07 AM

Theencoding/binarypackageinGoisessentialbecauseitprovidesastandardizedwaytoreadandwritebinarydata,ensuringcross-platformcompatibilityandhandlingdifferentendianness.ItoffersfunctionslikeRead,Write,ReadUvarint,andWriteUvarintforprecisecontroloverbinary

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Integrate Eclipse with SAP NetWeaver application server.

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software