在 Go 中我无法弄清楚如何获得以下设置。
- 第一级 goroutine 应该在终止之前停止其第二级 goroutine。
- 如果函数
runGoroutine
没有循环(我不希望它循环),那么当消息发送到通道时,goroutine 将如何退出?如果没有循环,那么case <-stopChan:
只会在开始时被调用一次。 - 如果函数
runGoroutine
调用其他异步函数会怎么样?当返回时这些函数也会退出吗?
也许我的方法不对。在我的情况下,我有x
用户可以启动的任务组,当用户启动任务组时,会创建一个 goroutine(第 1 级)以返回 CL 用户访问权限。此任务组(第 1 级)是y
API 请求的集合(实际上 y 是 200-300)。对于每个 API 请求,我都会创建一个新的 go-routine(第 2 级)。我的目标是速度;如果我每秒执行数百个 API 请求,将每个请求放入其自己的 goroutine 中是否更快/更有效?或者在 1 个线程上执行是否相同?
Parent/Main process
| |
Child goroutine Child goroutine
| |
X bottom goroutines X bottom goroutines (API level)
package main
import (
"fmt"
"time"
)
func runGoroutine(stopChan <-chan struct{}) {
for {
select {
case <-stopChan:
return // Exit the goroutine
default:
fmt.Println("Goroutine is working...")
time.Sleep(1 * time.Second)
}
}
}
func main() {
stopChan := make(chan struct{})
// Start the goroutine
go runGoroutine(stopChan)
// User should be able to close the routines they want
close(stopChan)
}
新代码
package main
import (
"context"
"log"
"net/http"
"sync"
"time"
)
func main() {
// Initialize context with cancellation
ctx, cancel := context.WithCancel(context.Background())
// Call the worker pool in a separate goroutine to allow main to return immediately
// We can start any task group like this
go startWorkerPool(ctx, 20, 100)
// User has CL access on main thread
// Main function returns, but `cancel` is accessible to allow later cancellation if needed
log.Println("Worker pool started; you can cancel it by calling cancel()")
waitForNine()
}
func waitForNine() {
var input int
for input != 9 {
fmt.Print("Enter a number: ")
fmt.Scan(&input)
}
}
// startWorkerPool starts a fixed-size worker pool to handle `numRequests` requests.
func startWorkerPool(ctx context.Context, numWorkers, numRequests int) {
var wg sync.WaitGroup
work := make(chan string)
// Launch the specified number of workers
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func(ctx context.Context) {
defer wg.Done()
client := http.Client{}
for url := range work {
if req, err := http.NewRequestWithContext(ctx, "GET", url, nil); err != nil {
log.Println("failed to create new request:", err)
} else if resp, err := client.Do(req); err != nil {
log.Println("failed to make request:", err)
} else {
resp.Body.Close()
}
}
}(ctx)
}
// Enqueue URLs for workers and close the channel when done
go func() {
for i := 0; i < numRequests; i++ {
work <- "https://httpbin.org/get"
}
close(work)
}()
// Wait for all workers to finish
wg.Wait()
log.Println("All requests processed")
}