[英]Sending value into Channel and Reading output when Ready
提示:本站为国内最大中英文翻译问答网站,提供中英文对照查看,鼠标放在中文字句上可显示英文原文。
我正在尝试使用 Golang 中的两个通道构建接收方和发送方模式。 我正在执行一项任务(API 调用),并收到一个Response
结构。 我的目标是,当收到响应时,我想将其发送到另一个通道 ( writeChan
) 以进行额外处理。
我想持续读取/收听该接收通道 ( respChan
) 并处理通过的任何内容(例如Response
)。 然后我想启动一个线程到 go 并在另一个 goroutine 中对该 Response 做进一步的操作。
我想了解如何将此模式链接在一起以允许数据从 API 调用流出并同时写入它(每个响应将写入Write()
函数处理的单独文件目标。
基本上我目前的模式如下:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
respChan := make(chan Response) // Response is a struct that contains API response metadata
defer close(respChan)
// requests is just a slice of requests to be made to an API
// This part is working well
for _, req := range requests {
wg.Add(1)
go func(r Request) {
defer wg.Done()
resp, _ := r.Get() // Make the API call and receive back a Response struct
respChan <- resp // Put the response into our channel
}(req)
}
// Now, I want to extract the responses as they become available and send them to another function to do some processing. This I am unsure of how to handle properly
writeChan := make(chan string)
defer close(writeChan)
select {
case resp := <-respChan: // receive from response channel
go func(response Response) {
signal, _ := Write(response) // Separate func to write the response to a file. Not important here in this context.
writeChan <- signal // Put the signal data into the channel which is a string file path of where the file was written (will be used for a later process)
}(resp)
case <-time.After(15 *time.Second):
fmt.Println("15 seconds have passed without receiving anything...")
}
wg.Wait()
}
让我与您分享一个您可以从中受益的工作示例。 首先,我将展示代码,然后,我将引导您完成所有相关部分。
package main
import (
"fmt"
"net/http"
"os"
"strings"
"time"
)
type Request struct {
Url string
DelayInSeconds time.Duration
}
type Response struct {
Url string
StatusCode int
}
func main() {
requests := []Request{
{"https://www.google.com", 0},
{"https://stackoverflow.com", 1},
{"https://www.wikipedia.com", 4},
}
respChan := make(chan Response)
defer close(respChan)
for _, req := range requests {
go func(r Request) {
fmt.Printf("%q - %v\n", r.Url, strings.Repeat("#", 30))
// simulate heavy work
time.Sleep(time.Second * r.DelayInSeconds)
resp, _ := http.Get(r.Url)
res := Response{r.Url, resp.StatusCode}
fmt.Println(time.Now())
respChan <- res
}(req)
}
writeChan := make(chan struct{})
defer close(writeChan)
for i := 0; i < len(requests); i++ {
select {
case res := <-respChan:
go func(r Response) {
f, err := os.Create(fmt.Sprintf("%v.txt", strings.Replace(r.Url, "https://", "", 1)))
if err != nil {
panic(err)
}
defer f.Close()
f.Write([]byte(fmt.Sprintf("%q OK with %d\n", r.Url, r.StatusCode)))
writeChan <- struct{}{}
}(res)
case <-time.After(time.Second * 2):
fmt.Println("Timeout")
}
}
}
首先,我定义了将在示例中使用的两个结构: Request
和Response
。 在前者中,我放了一个DelayInSeconds
来模拟一些重负载和耗时的操作。 然后,我定义了包含所有必须完成的请求的requests
变量。
在这里,我检查了requests
变量。 对于每个请求,我将向目标 URL 发出 HTTP 请求time.Sleep
模拟重负载。 然后,我将响应写入无缓冲的respChan
通道。
在这里,主要的变化是将select
构造包装到一个for
循环中。 多亏了这一点,我们将确保迭代正确的时间(基于requests
变量的长度)。
首先,请记住代码过于简单只是为了展示相关部分。 因此,缺少很多错误处理,一些内联函数可以外推到命名函数中。 你不需要使用sync.WaitGroup
来实现你需要的,使用通道就足够了。
随意玩延迟并检查写入了哪些文件!
让我知道这是否对您有帮助!
根据要求,我将根据您的需求为您提供更准确的解决方案。 新的阅读部分将类似于以下内容:
count := 0
for {
// this check is need to exit the for loop and not wait indefinitely
// it can be removed based on your needs
if count == 3 {
fmt.Println("all responses arrived...")
return
}
res := <-respChan
count++
go func(r Response) {
f, err := os.Create(fmt.Sprintf("%v.txt", strings.Replace(r.Url, "https://", "", 1)))
if err != nil {
panic(err)
}
defer f.Close()
f.Write([]byte(fmt.Sprintf("%q OK with %d\n", r.Url, r.StatusCode)))
writeChan <- struct{}{}
}(res)
}
在这里,执行在for
循环中无限期地等待。 无论每个请求需要多长时间才能完成,它都会在到达时立即获取。 我在for
循环的顶部放置了一个if
语句,以便在它处理完我们需要的请求后退出。 但是,您可以避免它并让代码运行直到出现取消信号(由您决定)。
让我知道这是否更符合您的要求,谢谢!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.