Home  >  Article  >  Backend Development  >  Reading multiple return values ​​from goroutine

Reading multiple return values ​​from goroutine

PHPz
PHPzforward
2024-02-09 12:30:091054browse

从 goroutine 读取多个返回值

php Editor Apple Reading multiple return values ​​from goroutine is a common operation in the Go language. Goroutine is a lightweight thread in the Go language that can achieve concurrent execution. In some cases, we need to get the return value from one or more goroutines for further processing. This operation can be achieved by using channels, which are an important mechanism for communication between goroutines. Through channels, we can pass data between goroutines and achieve synchronization and communication between coroutines. In this article, we will detail the tips and considerations on how to read multiple return values ​​from a goroutine.

Question content

I'm trying to write wc(1) in Go, and I'm trying to use goroutines to compute a large number of input files more efficiently. My code works fine, but I'm having trouble implementing a way to summarize statistics for all go routines. How can I pass the function variables nl, nw, nc to main and aggregate them there after all the go routines have finished their work?

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func main() {
    ch := make(chan string)

    for _, arg := range os.Args[1:] {
        go wc(arg, ch)
    }
    for range os.Args[1:] {
        fmt.Println(<-ch)
    }
    // Todo: summarize results...
}

func wc(arg string, ch chan<- string) {
    nl, nw, nc := 0, 0, 0

    file, err := os.Open(arg)
    if err != nil {
        fmt.Println("Can't open file: %v", err)
    }
    defer file.Close()

    scan := bufio.NewScanner(file)
    for scan.Scan() {
        nl++

        line := scan.Text()
        words := bufio.NewScanner(strings.NewReader(line))
        words.Split(bufio.ScanWords)
        for words.Scan() {
            nw++
        }

        runes := bufio.NewReader(strings.NewReader(line))
        for {
            if _, _, err := runes.ReadRune(); err != nil {
                break
            } else {
                nc++
            }
        }
    }

    ch <- fmt.Sprintf("%8d%8d%8d", nl, nw, nc+nl)
}

Solution

You are close to the answer! I'd suggest a quick refactor to return a Result object with numbers, which would allow adding them at the end easily (instead of using a string). Therefore, you can use chan result instead of chan string.

Basically, you can introduce a totalResult variable and when iterating over all results, just add nl, nc and nw# The result of ## is added to this total variable.

<code>package main

import (
    "fmt"
    "math/rand"
)

// define a struct to hold the result
type Result struct {
    nl int
    nw int
    nc int
}

// this is to be able to use fmt.Println(result)
func (r Result) String() string {
    return fmt.Sprintf("%8d%8d%8d", r.nl, r.nw, r.nc+r.nl)
}

func main() {
    ch := make(chan Result)

    for _, arg := range os.Args[1:] {
        go wc(arg, ch)
    }

    totalResult := Result{}

    for range os.Args[1:] {
        result := <-ch
        fmt.Println(result) // just for debugging

        // sum everything
        totalResult.nl += result.nl
        totalResult.nw += result.nw
        totalResult.nc += result.nc
    }

    fmt.Println("Total result:")
    fmt.Println(totalResult)
}

func wc(arg string, ch chan<- Result) {
    nl, nw, nc := 0, 0, 0

    // your logic to compute nl, nw, nc goes here

    ch <- Result{nl: nl, nw: nw, nc: nc + nl}
}
</code>

You should get something like this (containing 3 files):

37      50    4753
      19     106     821
      47     255    3806
Total result:
     103     411    9380

The above is the detailed content of Reading multiple return values ​​from goroutine. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete