Golang - Go 例程和通道有一些问题
Golang - Have some troubles with Go-routines and channels
我对 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
<-d
wg.Done()
FinishedTime := time.Now().UTC().Format(time.RFC3339)
qwe=append(qwe,outputURLs{
jobID:jobID,
retro:pol,
CreateTime: CreateTime,
FinishedTime: FinishedTime,
})
fmt.Println(jobID)
所以我觉得我的渠道和套路不行。它确实在上传任务之前打印出 jobID。而且上传对于异步上传来说似乎太慢了。
我知道代码有点乱,很抱歉。非常感谢任何帮助!提前致谢!
您实际上没有正确使用 WaitGroup
。每次你调用 wg.Done()
它实际上是从之前的 wg.Add
中减去 1 以确定给定任务已完成。最后,您需要一个 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")
我要注意的另一件事是,在您当前的代码示例中,您正在使用通道,但您没有对推送到通道中的值做任何事情,因此您可以从技术上删除它们。
您的代码有点混乱。但是,如果我正确理解您正在尝试做什么,您正在处理请求列表并希望 return 每个请求的 url 和状态以及每个请求完成的时间。并且您想并行处理这些。
您根本不需要使用 WaitGroups。当您只想 运行 一堆任务而不关心结果,只想知道一切何时完成时,WaitGroups 非常有用。但是,如果您要 return 获取结果,渠道就足够了。
这是一个示例代码,可以执行我认为您正在尝试执行的操作
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 列表大小相同的频道。这对于几个 urls 会很好地工作,但是如果您有一个包含一百万 urls 的列表,您将创建一个相当大的频道。您可能希望将通道缓冲区大小固定为某个合理的值,并在发送请求之前检查通道是否已准备好进行处理。这样你就可以避免一次发出一百万个请求。
我对 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
<-d
wg.Done()
FinishedTime := time.Now().UTC().Format(time.RFC3339)
qwe=append(qwe,outputURLs{
jobID:jobID,
retro:pol,
CreateTime: CreateTime,
FinishedTime: FinishedTime,
})
fmt.Println(jobID)
所以我觉得我的渠道和套路不行。它确实在上传任务之前打印出 jobID。而且上传对于异步上传来说似乎太慢了。
我知道代码有点乱,很抱歉。非常感谢任何帮助!提前致谢!
您实际上没有正确使用 WaitGroup
。每次你调用 wg.Done()
它实际上是从之前的 wg.Add
中减去 1 以确定给定任务已完成。最后,您需要一个 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")
我要注意的另一件事是,在您当前的代码示例中,您正在使用通道,但您没有对推送到通道中的值做任何事情,因此您可以从技术上删除它们。
您的代码有点混乱。但是,如果我正确理解您正在尝试做什么,您正在处理请求列表并希望 return 每个请求的 url 和状态以及每个请求完成的时间。并且您想并行处理这些。
您根本不需要使用 WaitGroups。当您只想 运行 一堆任务而不关心结果,只想知道一切何时完成时,WaitGroups 非常有用。但是,如果您要 return 获取结果,渠道就足够了。
这是一个示例代码,可以执行我认为您正在尝试执行的操作
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 列表大小相同的频道。这对于几个 urls 会很好地工作,但是如果您有一个包含一百万 urls 的列表,您将创建一个相当大的频道。您可能希望将通道缓冲区大小固定为某个合理的值,并在发送请求之前检查通道是否已准备好进行处理。这样你就可以避免一次发出一百万个请求。