停止所有正在运行的嵌套循环 for -> go funC语言 > for 循环



我发现如何"多线程";每次使用不同代理的请求都是将一个go func和for循环嵌套在另一个for循环中,但我不知道如何像中断正常情况下那样停止所有循环,我尝试了常规中断,也尝试了中断和添加:在循环之上,但这并没有停止。

package main
import (
"log"
"encoding/json"
"github.com/parnurzeal/gorequest"
)
func main(){
rep := 100 
for i := 0; i < rep; i++ { 
log.Println("starting loop")
go func() { 
for{
request := gorequest.New()
resp, body, errs := request.Get("https://discord.com/api/v9/invites/family").End()
if errs != nil {
return
}
if resp.StatusCode == 200{
var result map[string]interface{}
json.Unmarshal([]byte(body), &result)
serverName := result["guild"].(map[string]interface{})["name"]       
log.Println(sererName +" response 200, closing all loops")
//break all loops and goroutine here
}
}
}
}
log.Println("response 200,closed all loops")

使用parnurzeal/gorequest会使回答此问题变得复杂,因为该包没有提供任何明显的取消请求的方法(请参阅此问题(。因为你的重点似乎是过程,而不是特定的函数,所以我刚刚使用了标准库(http((如果你确实需要使用gorequest,那么可能会专门问一个问题(。

无论如何,下面的解决方案展示了一些东西:

  • 使用一个Waitgroup,这样它就知道什么时候所有的go例程都完成了(这里不重要,但你经常想知道你已经干净地关闭了(
  • 通过通道传递结果(从goroutine更新共享变量会导致数据竞赛(
  • 使用上下文进行取消。当我们得到结果时会调用cancel函数,这将停止正在进行的请求
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
"sync"
)
func main() {
// Get the context and a function to cancel it
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // Not really required here but its good practice to ensure context is cancelled eventually.
results := make(chan string)
const goRoutineCount = 100
var wg sync.WaitGroup
wg.Add(goRoutineCount) // we will be waiting on 100 goRoutines
for i := 0; i < goRoutineCount; i++ {
go func() {
defer wg.Done() // Decrement WaitGroup when goRoutine exits
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://discord.com/api/v9/invites/family", nil)
if err != nil {
panic(err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
if errors.Is(err, context.Canceled) {
return // The error is due to the context being cancelled so just shutdown
}
panic(err)
}
defer resp.Body.Close() // Ensure body is closed
if resp.StatusCode == 200 {
var result map[string]interface{}
if err = json.NewDecoder(resp.Body).Decode(&result); err != nil {
panic(err)
}
serverName := result["guild"].(map[string]interface{})["name"]
results <- serverName.(string) // Should error check this...
cancel()                       // We have a result so all goroutines can stop now!
}
}()
}
// We need to process results until everything has shutdown; simple approach is to just close the channel when done
go func() {
wg.Wait()
close(results)
}()
var firstResult string
requestsProcessed := 0
for x := range results {
fmt.Println("got result")
if requestsProcessed == 0 {
firstResult = x
}
requestsProcessed++ // Possible that we will get more than one result (remember that requests are running in parallel)
}
// At this point all goroutines have shutdown
if requestsProcessed == 0 {
log.Println("No results received")
} else {
log.Printf("xx%s response 200, closing all loops (requests processed: %d)", firstResult, requestsProcessed)
}
}

相关内容

最新更新