为了账号安全,请及时绑定邮箱和手机立即绑定

Golang - Go 例程和通道有一些问题

Golang - Go 例程和通道有一些问题

Go
慕村225694 2023-04-24 16:31:54
我对 Golang 有点陌生,正在尝试开发一个将图像异步上传到 imgur 的程序。但是我的代码遇到了一些困难。所以这是我的任务;func uploadT(url string,c chan string, d chan string)  {    var subtask string    subtask=upload(url)    var status string    var url string    if subtask!=""{        status = "Success!"        url =subtask    } else {        status = "Failed!"        url =subtask    }    c<-url    d<-status}这是我用于异步上传的 POST 请求循环;c:=make(chan string, len(js.Urls))d:=make(chan string, len(js.Urls))wg:=sync.WaitGroup{}for i := range js.Urls{    wg.Add(1)    go uploadTask(js.Urls[i],c,d)    //Below commented out code is slowing down the routine therefore, I commented out.    //Needs to be working as well, however, it can work if I put this on task as well. I think I'm kinda confused with this one as well    //pol=append(pol,retro{Url:<-c,Status:<-d})}<-c<-dwg.Done()FinishedTime := time.Now().UTC().Format(time.RFC3339)qwe=append(qwe,outputURLs{               jobID:jobID,               retro:pol,               CreateTime: CreateTime,               FinishedTime: FinishedTime,           })fmt.Println(jobID)所以我觉得我的渠道和套路不行。它确实在上传任务之前打印出 jobID。而且上传对于异步上传来说似乎太慢了。我知道代码有点乱,对此感到抱歉。非常感谢任何帮助!提前致谢!
查看完整描述

2 回答

?
Cats萌萌

TA贡献1805条经验 获得超9个赞

你实际上没有WaitGroup正确使用。每次你调用wg.Done()它实际上是从前一个中减去 1wg.Add以确定给定的任务已完成。最后,您需要wg.Wait()同步等待所有任务。WaitGroups通常用于并行运行多个任务的扇出使用。


根据您的代码示例,最简单的方法是将 传入wg您的任务,然后在任务内部uploadT调用。wg.Done()请注意,您还需要使用指针而不是结构值。


下一个实现细节是在循环外调用wg.Wait(),因为你想阻塞直到所有任务都完成,因为你的所有任务都在运行,go这使得它异步。如果你不这样做wg.Wait(),它会像你说的那样立即记录jobID。让我知道是否清楚。


作为样板,它应该看起来像这样


func task(wg *sync.WaitGroup) {

    wg.Done()

}


wg := &sync.WaitGroup{}

for i := 0; i < 10; i++ {

    wg.Add(1)

    go task(wg)

}


wg.Wait()

// do something after the task is done

fmt.Println("done")

我要注意的另一件事是,在您当前的代码示例中,您正在使用通道,但您没有对推送到通道中的值做任何事情,因此您可以从技术上删除它们。


查看完整回答
反对 回复 2023-04-24
?
翻阅古今

TA贡献1780条经验 获得超5个赞

你的代码有点混乱。但是,如果我理解正确你正在尝试做什么,你正在处理一个请求列表,并希望返回每个请求的 url 和状态以及每个请求完成的时间。并且您想并行处理这些。


您根本不需要使用 WaitGroups。当您只想运行一堆任务而不关心结果,只想知道一切何时完成时,WaitGroups 非常有用。但如果你要返回结果,渠道就足够了。


这是一个示例代码,可以执行我认为您正在尝试执行的操作


package main


import (

    "time"

    "fmt"

)


type Result struct {

    URL      string

    Status   string

    Finished string

}


func task(url string, c chan string, d chan string) {

    time.Sleep(time.Second)

    c <- url

    d <- "Success"

}


func main() {

    var results []Result

    urls := []string{"url1", "url2", "url3", "url4", "url5"}

    c := make(chan string, len(urls))

    d := make(chan string, len(urls))

    for _, u := range urls {

        go task(u, c, d)

    }

    for i := 0; i < len(urls); i++ {

        res := Result{}

        res.URL = <-c

        res.Status = <-d

        res.Finished = time.Now().UTC().Format(time.RFC3339)

        results = append(results, res)

    }

    fmt.Println(results)

}

你可以在操场上试试https://play.golang.org/p/N3oeA7MyZ8L


也就是说,这有点脆弱。您正在制作与网址列表大小相同的频道。这对于一些 url 来说效果很好,但是如果你有一个包含一百万个 url 的列表,你将创建一个相当大的频道。您可能希望将通道缓冲区大小固定为某个合理的值,并在发送请求之前检查通道是否已准备好进行处理。这样你就可以避免一次发出一百万个请求。


查看完整回答
反对 回复 2023-04-24
  • 2 回答
  • 0 关注
  • 68 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信