golang聚合处理,批次处理100条数据,不满100条过期1s自动提交

处理channel 100条数据写入一批数据,超过1s自动提交

package main

import (
	"io"
	"log"
	"math/rand"
	"os"
	"strconv"
	"strings"
	"time"
)

type LogBatch struct {
	Logs []string
}

type LogSink struct {
	logChan        chan string
	autoCommitChan chan *LogBatch // 超时通知
}


func main()  {
	logFile, err := os.OpenFile("test.log", os.O_CREATE | os.O_APPEND | os.O_RDWR, 0666)
	if err != nil {
		panic(err)
	}
	defer logFile.Close()
	mw := io.MultiWriter(os.Stdout,logFile)
	log.SetOutput(mw)
	logSink := &LogSink{
		logChan:        make(chan string, 2000),
		autoCommitChan: make(chan *LogBatch, 1000),
	}

	go logSink.writeLoop()
	page := 1
	for{
		time.Sleep(time.Millisecond * time.Duration(rand.Intn(500) + 700))
		for i := (page-1)*50; i< 50*page;i++ {
			logSink.logChan <- strconv.Itoa(i)
		}
		page++
	}
}



func (c *LogSink)writeLoop() {

	var (
		limit        = 100 // 100 条写入一次
		logStr       string
		logBatch     *LogBatch
		commitTimer  *time.Timer // 超时自动提交
		timeOutBatch *LogBatch
	)

	for {
		select {
		case logStr = <-c.logChan:
			if logBatch == nil {
				logBatch = &LogBatch{}

				commitTimer = time.AfterFunc(
					1*time.Second, func(logBatch *LogBatch) func() {
						return func() {
							// 批次传出来防止并发处理,进行串行处理
							c.autoCommitChan <- logBatch
						}
					}(logBatch),
				)

			}

			logBatch.Logs = append(logBatch.Logs, logStr)
			if len(logBatch.Logs) >= limit {
				// 发送日志 批量插入
				//time.Sleep(100*time.Millisecond) // gxz 加上,测试 timeOutBatch != logBatch 情况
				commitTimer.Stop() // 管定时器
				log.Println(strings.Join(logBatch.Logs, "|"))
				// 处理业务逻辑
				logBatch = nil

			}
		case timeOutBatch = <-c.autoCommitChan:
			// 第一种情况
			// 防止logBatch 刚好打满100 条, logBatch 开始成 nil 重复写入日志 stop 没有即时停止,超时批次 != nil
			// 刚好打了100条,limit 区间和 超时区间同时执行了,判断logBatch 不为nil
			// 第二种情况, autoCommitChan 提交了,但是 logBatch 上面新增了一条新数据或者多条,这时候,就出现了重复提交了,需要跳过
			if timeOutBatch != logBatch {
			
	
				continue
			}
			// 超时批量插入
			log.Println("超时:", strings.Join(timeOutBatch.Logs, "|"))
			// 处理业务逻辑 

			logBatch = nil // 清空批次
		}
	}

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Go语言中,可以使用heap(堆)数据结构来实现top k问题。下面是一个参考实现: ```go package main import ( "container/heap" "fmt" ) type Item struct { value string priority int index int } type PriorityQueue []*Item func (pq PriorityQueue) Len() int { return len(pq) } func (pq PriorityQueue) Less(i, j int) bool { return pq[i].priority > pq[j].priority } func (pq PriorityQueue) Swap(i, j int) { pq[i], pq[j] = pq[j], pq[i] pq[i].index = i pq[j].index = j } func (pq *PriorityQueue) Push(x interface{}) { n := len(*pq) item := x.(*Item) item.index = n *pq = append(*pq, item) } func (pq *PriorityQueue) Pop() interface{} { old := *pq n := len(old) item := old[n-1] item.index = -1 *pq = old[0 : n-1] return item } func main() { // 初始化一个容量为10的小根堆 pq := make(PriorityQueue, 0) heap.Init(&pq) // 模拟从数据源不断获取数据,并加入小根堆 for i := 1; i <= 100000000; i++ { value := fmt.Sprintf("data-%d", i) priority := i item := &Item{ value: value, priority: priority, } if pq.Len() < 10 { heap.Push(&pq, item) } else if item.priority > pq[0].priority { heap.Pop(&pq) heap.Push(&pq, item) } } // 输出堆中的前10个元素 for pq.Len() > 0 { item := heap.Pop(&pq).(*Item) fmt.Printf("%s: %d\n", item.value, item.priority) } } ``` 该实现中,使用一个容量为10的小根堆,从数据源中不断获取数据,并将数据加入小根堆中。如果堆的大小小于10,直接加入堆中;否则,比较当前数据的优先级(即数据的大小),如果比堆顶元素大,则弹出堆顶元素,将当前数据加入堆中。最后输出堆中的前10个元素,即为top 10。 需要注意的是,这种方法只适用于数据量比较小的情况,如果数据量非常大,可能会导致内存溢出。在实际使用中,可以考虑使用分布式计算框架,例如Hadoop或Spark,来处理大规模数据集。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gitxuzan_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值