当前位置: 首页 > 面试题库 >

使用sync.WaitGroup和频道的Golang应用程序永不退出

党源
2023-03-14
问题内容

我使用sync.WaitGroupdefer wg.Close()wg.Wait()等待goroutine完成。

该程序确实会等待,但是它永远不会退出。

这是我的程序(可运行):

package main

import (
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
    "sync"
)

var symbols = []string{
    "ASSA-B.ST",
    "ELUX-B.ST",
    "HM-B.ST",
}

func main() {

    fmt.Println("fetching quotes...")

    fetchedSymbols := make(chan string)
    var wg sync.WaitGroup
    wg.Add(len(symbols))

    for _, symbol := range symbols {
        go fetchSymbol(symbol, &wg, fetchedSymbols)
    }

    for response := range fetchedSymbols {
        fmt.Println("fetched " + response)
    }

    wg.Wait()

    fmt.Println("done")

}

func fetchSymbol(symbol string, wg *sync.WaitGroup, c chan<- string) {
    defer wg.Done()
    resp, err := http.Get("http://ichart.yahoo.com/table.csv?s=" + symbol + "&a=0&b=1&c=2000")
    defer resp.Body.Close()

    if err != nil {
        log.Fatal(err)
    }

    out, err := os.Create("./stock-quotes/" + symbol + ".csv")
    defer out.Close()

    if err != nil {
        log.Fatal(err)
    }

    io.Copy(out, resp.Body)
    c <- symbol
}

下载所有报价后,该程序是否应该退出?(仅供参考:我刚刚开始学习GO)


问题答案:

您永远不会关闭fetchedSymbols通道,因此范围循环永远不会退出。

解决此问题的一种方法是使用WaitGroup,您已经必须在关闭通道时发出信号。调整范围fetchedSymbols足以阻止main中的进度,并且您不需要其他通道或WaitGroup。

...
go func() {
    wg.Wait()
    close(fetchedSymbols)
}()

for response := range fetchedSymbols {
    fmt.Println("fetched " + response)
}

...


 类似资料:
  • 高朗新手来了。我正在尝试围棋之旅,遇到了一个关于渠道(https://tour.golang.org/concurrency/7)的练习。这个想法是走两棵树,然后评估这些树是否相等。 我想使用select等待两个通道的结果来解决此练习。当这两个都完成时,我对结果切片进行评估。不幸的是,该方法在无限循环中进行。我添加了一些输出以查看发生了什么,并注意到只有一个通道被关闭,然后再次打开。 我显然做错了

  • 我试图为管道开发一个应用程序: gst-launch-1.0 rtspsrc位置=”rtsp://192.168.3.30:8554/rajvi“延迟=0 name=demux demux。!queue!rtpmp4gdepay!aacparse!avdec\u aac!audioconvert!audioresample!autoaudiosink demux。!queue!rtph264dep

  • 问题内容: 我正在学习Go,并且遇到了以下代码片段: 有人可以告诉我为什么“ sum”函数的第二个调用在第一个调用之前通过通道吗?在我看来,输出应为: 我还使用无缓冲通道对此进行了测试,它也给出了相同顺序的输出。我想念什么? 问题答案: 您正在代码中调用go例程,但无法确定例程何时结束并将该值传递到缓冲通道。 由于该代码是异步的,因此只要例程完成,它将把数据写入通道,并在另一侧读取。在上面的示例中

  • 问题内容: 我的应用程序包含A,B和C这三个活动。我通过“确定”按钮从A移到B,并且我想使用Android设备的默认后退按钮从B移到A。但是,当我按下按钮时,整个应用程序将关闭。我该如何解决这个问题? 问题答案: 我怀疑您是通过“确定”按钮onclick监听器调用的。不要那样做 从活动堆栈中删除您的活动。 在这里阅读更多。

  • 问题内容: 在过去的几天里,我一直在尝试通过重构我的一个命令行实用程序来在Golang中进行并发,但是我被困住了。 这是原始代码(master分支)。 这是并发分支(x_concurrent分支)。 当我使用执行并发代码时,如果将JIRA问题添加到此处的通道,则永不执行,这将导致我永远挂起。 我的想法是,我有大量的JIRA问题,我想为每个goroutine编写一个goroutine,以查看是否需要

  • 问题内容: 我制作了一个命令行应用程序,在其中压缩文件夹并在本地服务器上共享供他人下载。我想做的是关闭服务器后立即删除压缩文件夹的副本。这是我的代码: 当我按下ctrl- c时,程序退出并且main函数关闭,结果,是否应该执行os.Remove(xyz)?去的游览说,推迟执行该表达式时,函数返回。在这里,我不觉得main有机会退还任何东西。 有什么解决方法可以实现我要完成的任务?我脑子里有一些解决