我很新golang.所以,请把剑给我(如果可能的话).
现在,教程一切顺利,但我想检查边缘情况和错误处理(只是为了彻底了解我对语言的新学习,不想成为具有半生不熟的知识的人).
这是我的游乐场代码.
在询问之前我看过很多参考资料,例如:
还有一些,但我无法弄明白.
这是代码,以防您不想去操场(原因尚不为人所知):
// MakeRequest : Makes requests concurrently
func MakeRequest(url string, ch chan<- string, wg *sync.WaitGroup) {
start := time.Now()
resp, err := http.Get(url)
defer func() {
resp.Body.Close()
wg.Done()
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
if err != nil {
fmt.Println(err)
panic(err)
}
secs := time.Since(start).Seconds()
body, _ := ioutil.ReadAll(resp.Body)
ch <- fmt.Sprintf("%.2f elapsed with response length: %d %s", secs, len(body), url)
}
func main() {
var wg sync.WaitGroup
output := []string{
"https://www.facebook.com",
"",
}
start := time.Now()
ch := make(chan string)
for _, url := range output {
wg.Add(1)
go MakeRequest(url, ch, &wg)
}
for range output {
fmt.Println(<-ch)
}
fmt.Printf("%.2fs elapsed\n", time.Since(start).Seconds())
}
Run Code Online (Sandbox Code Playgroud)
我改变了代码(让我们说)处理像goroutine这样的错误(go-playground here):
func MakeRequest(url string, ch chan<- string, wg *sync.WaitGroup) {
start := time.Now()
resp, err := http.Get(url)
if err == nil {
secs := time.Since(start).Seconds()
body, _ := ioutil.ReadAll(resp.Body)
ch <- fmt.Sprintf("%.2f elapsed with response length: %d %s", secs, len(body), url)
// fmt.Println(err)
// panic(err)
}
defer wg.Done()
}
Run Code Online (Sandbox Code Playgroud)
在答案之后我将代码更改为此并且它成功地删除了chan死锁,但是现在我需要处理这个main:
func MakeRequest(url string, ch chan<- string, wg *sync.WaitGroup) {
defer wg.Done()
start := time.Now()
resp, err := http.Get(url)
if err == nil {
secs := time.Since(start).Seconds()
body, _ := ioutil.ReadAll(resp.Body)
ch <- fmt.Sprintf("%.2f elapsed with response length: %d %s", secs, len(body), url)
// fmt.Println(err)
// panic(err)
}
// defer resp.Body.Close()
ch <- fmt.Sprintf("")
}
Run Code Online (Sandbox Code Playgroud)
难道没有更优雅的方式来处理这个问题吗?
但现在我陷入了僵局.
感谢致敬.
Temporarya
(golang noobie)
您正在使用正确恢复.你有两个问题:
您错误地使用恐慌.只有在出现编程错误时才应该发生恐慌.避免使用恐慌,除非您认为取消该计划是对发生的事情的合理回应.在这种情况下,我只会返回错误,而不是恐慌.
你在恐慌期间惊慌失措.发生了什么事情,你是第一次惊慌失措panic(err).然后在你的延迟函数中,你正在惊慌失措resp.Body.Close().当http.Get返回错误时,它返回一个nil响应.这意味着它resp.Body.Close()的作用是零值.
解决这个问题的惯用方法如下:
func MakeRequest(url string, ch chan<- string, wg *sync.WaitGroup) {
defer wg.Done()
start := time.Now()
resp, err := http.Get(url)
if err != nil {
//handle error without panicing
}
// there was no error, so resp.Body is guaranteed to exist.
defer resp.Body.Close()
...
Run Code Online (Sandbox Code Playgroud)
对更新的响应:如果http.Get()返回错误,则永远不会发送通道.在某些时候,除了主要的goroutine之外的所有goroutine停止运行并且主要的goroutine正在等待<-ch.由于该通道接收将永远不会完成,并且Go运行时没有其他任何安排,它会发生恐慌(不可恢复).
对评论的回应:为了确保频道不会挂起,您需要某种协调来了解消息何时停止.如何实现这取决于你的真实程序,一个例子不一定能推断到现实.对于这个例子,我只是在WaitGroup完成时关闭通道.
func main() {
var wg sync.WaitGroup
output := []string{
"https://www.facebook.com",
"",
}
start := time.Now()
ch := make(chan string)
for _, url := range output {
wg.Add(1)
go MakeRequest(url, ch, &wg)
}
go func() {
wg.Wait()
close(ch)
}()
for val := range ch {
fmt.Println(val)
}
fmt.Printf("%.2fs elapsed\n", time.Since(start).Seconds())
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
451 次 |
| 最近记录: |