我正在学习go lang,我想创建一个go应用来实现以下目的:
我一直在阅读有关并发性,并行性和 channel 的信息,但是我不确定如何将数据从我的日志记录goroutine传递到另一个带有计时器的例程来发出请求。我是否应该在另一个例程中声明一个分片以接收所有消息,并在计时器结束时对其进行迭代?
目前,我的代码如下所示:
package main
import (
"fmt"
"log"
"strings"
"gopkg.in/mcuadros/go-syslog.v2"
)
func strigAnalyze(str string){
/*analyse the contents of the log message and do something*/
}
func main() {
channel := make(syslog.LogPartsChannel)
handler := syslog.NewChannelHandler(channel)
server := syslog.NewServer()
server.SetFormat(syslog.RFC3164)
server.SetHandler(handler)
server.ListenUDP("0.0.0.0:8888")
server.ListenTCP("0.0.0.0:8888")
server.Boot()
go func(channel syslog.LogPartsChannel) {
for logParts := range channel {
content := logParts["content"]
fmt.Println("logparts", logParts)
string := fmt.Sprintf("%v", content)
strigAnalyze(str)
}
}(channel)
server.Wait()
}
最佳答案
我是否应该在另一个例程中声明一个片以接收所有
消息,最后计时器会对其进行迭代?
这是一种非常常见的模式。您描述的示例有时称为“monitor routine”。它保护日志缓冲区,并且因为它“拥有”它们,所以您知道它们可以防止并发访问。
数据是通过 channel 共享的,日志数据的产生者将与发送者的使用方式完全分离,它所要做的就是在 channel 上发送。如果 channel 没有缓冲,那么您的生产者将阻塞,直到接收者可以处理为止。如果需要保持生产者高吞吐量,则可以缓冲channel或shed sends,如下所示:
select {
case logChan <- log:
...
default:
// chan is full shedding data.
}
这种模式也非常适合在输入 channel ,计时器和某种完成/上下文中通过
for...selects
进行的“接收”循环。以下不是一个有效的示例,它缺少取消和逻辑,但是它说明了如何在多个 channel 上进行选择(其中一个是计时器/心跳):logChan := make(chan string)
go func() {
var logBuf []string
t := time.NewTimer(time.Second * 5)
for {
select {
log, ok := <-logChan:
if !ok { return }
logBuf = append(logBuf, log)
<-t.C:
// timer up
// flush logs
// reset slice
}
}
}()
另外,根据您使用数据的方式,在此处使用实际缓冲区而不是 slice 可能更有意义。
关于go - 从go例程中堆叠数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61372908/