Go并发模式之队列

带缓存的 channel, 其实就是一种队列。
引入队列,通常是优化程序时希望采用的最后一种技术之一。预先添加队列可以隐藏同步问题,例如死锁,和活锁。
常见错误认识: 引入队列来尝试解决性能问题,队列几乎不会加速程序的总运行时间,它只会让程序的行为有所不同。
举例如下:
图 todo
看看如下这个pipeline:
p := processRequest(done, acceptConnection(done, httpHandler))

这个情景中可以引入队列: 结果并不是一个 stage 的运行时间已经减少了,而是它处于阻塞状态的时间减少了,这可以让这个stage 继续工作。
这个例子中,用户可能会 感受到它们的请求相应滞后, 但它们不会被拒绝服务。
问题: 队列应该放在哪里? 缓冲区大小应该是多少? 这些问题取决于管道的性质。

队列可以提高整体性能的情况 。唯一适用情况是:(满足的条件)
1。 如果一个stage 批处理 可以节省时间
2。 将输入缓冲到 比 设计为发送给(盘)更快的事物  如(存储器,内存) 的stage

例子: Go 语言的bufio 包, 下面一个示例,演示了 缓冲写入队列与 未缓冲写入的简单比较。

/**
下面的例子演示了缓冲写入队列与未缓冲写入的简单比较。
 */

func BenchmarkUnbufferedWrite(b *testing.B){
	performWrite(b, tmpFileOrFatal())
}

func BenchmarkBufferedWrite(b *testing.B){
	bufferedFile := bufio.NewWriter(tmpFileOrFatal())
	performWrite(b, bufio.NewWriter(bufferedFile))
}

func tmpFileOrFatal() *os.File{
	file, err := ioutil.TempFile("", "tmp")
	if err != nil{
		log.Fatalf("error: %v", err)
	}

	return file
}

func performWrite(b *testing.B , write io.Writer){
	done := make(chan interface{})
	defer close(done)

	b.ResetTimer()
	for bt := range take(done, repeat(done, byte(0)), b.N){
		write.Write([]byte{bt.(byte)})
	}
}
//BenchmarkUnbufferedWrite-8   	  200000	      8720 ns/op
//BenchmarkBufferedWrite-8     	 1000000	      1270 ns/op
//BenchmarkUnbufferedWrite-8      200000         8720 ns/op
//BenchmarkBufferedWrite-8          1000000         1270 ns/op
/**
通常 任何时候 执行操作都需要开销, 分块可能会提高系统性能。这方面的例子是打开数据库事务,就算消息校验和 以及分配连续空间。

通过在管道入口 引入队列,可以用创建请求滞后为代价 来 打破反馈循环。从调用者进入管道角度来看,请求似乎正在处理中,但需要很长时间。

排队模式:
在管道入口处。
在这个stage, 批量操作将会带来更高的效率。

队列理论/利特尔法则 todo

利特尔法则 无法预知的情况是处理请求的失败。如果由于某种原因你的管道发生混乱,你将丢失队列中所有请求。为了缓解这种情况,可以
坚持队列大小为0, 或者可以转移到一个持久队列。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Machinery 是一个 Go 语言的异步任务队列和作业队列,基于分布式消息传递。类似 Python 的 Celery 框架。Machinery 中的任务(或者作业)可通过多个 worker 在很多服务器上并发的执行,或者可在单个服务器上利用 Go 的协程运行多个 worker 进程。任务的定义:type AddTask struct{} func (t AddTask) Run(args []interface{}) (interface{}, error) {     parsedArgs, err := machinery.ParseNumberArgs(args)     if err != nil {         return nil, err     }     add := func(args []float64) float64 {         sum := 0.0         for _, arg := range args {             sum  = arg         }         return sum     }     return add(parsedArgs), nil } type MultiplyTask struct{} func (t MultiplyTask) Run(args []interface{}) (interface{}, error) {     parsedArgs, err := machinery.ParseNumberArgs(args)     if err != nil {         return nil, err     }     multiply := func(args []float64) float64 {         sum := 1.0         for _, arg := range args {             sum *= arg         }         return sum     }     return multiply(parsedArgs), nil } // ... more tasks任务注册:tasks := map[string]machinery.Task{     "add":      AddTask{},     "multiply": MultiplyTask{}, } app.RegisterTasks(tasks) 标签:GoMachinery

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值