文档章节

go-channel处理高并发请求

o
 osc_zoa3moe9
发布于 2019/12/08 16:57
字数 1216
阅读 34
收藏 0

精选30+云产品,助力企业轻松上云!>>>

go-channel处理高并发请求

[TOC]

最近看了一篇文章讲解怎样使用go-channel的,周末就花了点时间学习了一下,文章原文地址:

http://marcio.io/2015/07/handling-1-million-requests-per-minute-with-golang/ ,然后自己进行了一个简单的性能测试。

一、Channel简介

下面是go by example中的 一个简单的channel使用的例子:

package main
import "fmt"
func main() {
    messages := make(chan string)
    go func() { messages <- "ping" }()
    msg := <-messages
    fmt.Println(msg)
}

通道 是连接多个 Go 协程的管道。你可以从一个 Go 协程将值发送到通道,然后在别的 Go 协程中接收。使用 make(chan val-type) 创建一个新的通道。通道类型就是他们需要传递值的类型。使用 channel <- 语法 发送 一个新的值到通道中。这里我们在一个新的 Go 协程中发送 "ping" 到上面创建的messages 通道中。使用 <-channel 语法从通道中 接收 一个值。这里将接收我们在上面发送的 "ping" 消息并打印出来。我们运行程序时,通过通道,消息 "ping" 成功的从一个 Go 协程传到另一个中。

$ go run channels.go
ping

默认发送和接收操作是阻塞的,直到发送方和接收方都准备完毕。这个特性允许我们,不使用任何其它的同步操作,来在程序结尾等待消息 "ping"。channel也有带缓冲的可以不阻塞直接写到缓冲去(在缓冲没有满的情况下)。更多例子请参考: https://books.studygolang.com/gobyexample/channels/

二、处理包并发请求

上面那篇作者写的分钟处理百万请求文章,代码摘抄了一部分进行分析。下面是关键的几个数据结构:

  • 任务,用来需要表示一个需要处理的逻辑
// Job代表一个任务,根据自己需求定义
type Job struct {
	Id      string
	Payload string
}
  • worker, 用来处理任务的实例
// Worker用来处理job的实例
type Worker struct {
	WorkerPool chan chan Job //需要注册到的worker池
	JobChannel chan Job      //用来接受任务的通道
	quit       chan bool
}
  • Dispatcher, 用来分发job的实例
type Dispatcher struct { 
	WorkerPool chan chan Job //用来注册worker的池   
	MaxWorkers int           //worker最大个数
 }

初始化逻辑

func NewDispatcher(maxWorkers int) *Dispatcher {
	pool := make(chan chan Job, maxWorkers)
	return &Dispatcher{
		WorkerPool: pool, //初始化worker池
		MaxWorkers: maxWorkers,
	}
}

func (d *Dispatcher) Run() {
	for i := 0; i < d.MaxWorkers; i++ {
		//对每一个worker进行初始化,也就是将worker注册到池中,更直接点就是将每个worker的jobChannel放入到池中
		worker := NewWorker(d.WorkerPool)
		worker.Start()
	}
	go d.dispatch()
}

func NewWorker(workerPool chan chan Job) *Worker {
	return &Worker{
		WorkerPool: workerPool,
		JobChannel: make(chan Job),
		quit:       make(chan bool),
	}
}

//Start函数,启一个goroutine, 启动的时候将自己注册到worker池当中,然后就等待job被放到自己的jobChannel中
//一旦jobChannel中有job放入的时候,就开始处理这个job
//同时加入了一个quit channel可以用来控制销毁这个worker
func (w *Worker) Start() {
	go func() {
		for {
			w.WorkerPool <- w.JobChannel //注册当前这个worker到worker池中,
			// 也就是将自己的jobChannel放入到池中,用来接收job
			select {
			case job := <-w.JobChannel:
				//channel中放入了一个job
				if _, err := job.Done(); err != nil {
					//处理这个job
				}
			case <-w.quit:
				// 收到停止的信号,销毁这个worker
				return
			}
		}
	}()
}

任务分发逻辑

func (d *Dispatcher) dispatch() {
	for {
		select {
		case job := <-JobQueue:
			// 收到一个job
			go func(job Job) {
				// 从worker池中,选取一个worker的jobChannel,如果worker池中是空的,则会阻塞在这里
				jobChannel := <-d.WorkerPool
				// 将job放入到其中一个worker的jobChannel中,等待这个worker进行处理
				jobChannel <- job
			}(job)
		}
	}
}

三、测试

1、测试工具

ab, 下载地址: https://www.apachehaus.com/cgi-bin/download.plx

2、测试结果

$ ./abs -n 100000 -c 1000 "http://127.0.0.1:8080/job"
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests


Server Software:
Server Hostname:        127.0.0.1
Server Port:            8080

Document Path:          /job
Document Length:        0 bytes

Concurrency Level:      1000
Time taken for tests:   51.913 seconds
Complete requests:      100000
Failed requests:        1
   (Connect: 1, Receive: 0, Length: 0, Exceptions: 0)
Total transferred:      7500000 bytes
HTML transferred:       0 bytes
Requests per second:    1926.28 [#/sec] (mean)
Time per request:       519.134 [ms] (mean)
Time per request:       0.519 [ms] (mean, across all concurrent requests)
Transfer rate:          141.09 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   7.2      0    1007
Processing:    58  497 187.4    429    1448
Waiting:        6  348 195.3    315    1113
Total:         58  497 187.5    430    1449

Percentage of the requests served within a certain time (ms)
  50%    430
  66%    435
  75%    441
  80%    446
  90%    901
  95%    970
  98%   1014
  99%   1076
 100%   1449 (longest request)

测试结果感觉有点不太理想,不知道是不是因为电脑性能的原因还是参数设置的问题。在不用go-channel的测试和这个性能差不多,大家可以把这个代码下载下来自己测试一下,比对一下结果看看有没有优化的空间。

完整代码下载地址: https://gitee.com/ncuzhangben/GoStudy/tree/master/go-channel

o
粉丝 1
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
如何在 Swoole 中优雅的实现 MySQL 连接池

如何在 中优雅的实现 连接池 一、为什么需要连接池 ? 数据库连接池指的是程序和数据库之间保持一定数量的连接不断开, 并且各个请求的连接可以相互复用, 减少重复连接数据库带来的资源消耗...

osc_z97fe7xu
2019/06/19
2
0
nio、bio区别,应运场景

bio阻塞i/o a.面向流的,InputStream(),OuputStream字节输入流,字节输出流,Reader,Writer字符输入流,字符输出流 b.阻塞的IO,比如Socket,它的底层用的BIO机制,accept()、connect()、write...

osc_n1z6bj15
2019/02/27
2
0
Spring Boot 搭建TCP Server

本示例首选介绍Java原生API实现BIO通信,然后进阶实现NIO通信,最后利用Netty实现NIO通信及Netty主要模块组件介绍。 Netty 是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性...

osc_fted3syf
04/16
3
0
Netty 概述

Tomcat是基于Http协议的,实质是一个基于http协议的web容器; Netty能通过编程自定义各种协议,因为netty能够通过codec自己来编码/解码字节流。 netty的性能不一定比tomcat性能高,tomcat从6...

noob_fly
2019/01/17
4
0
Golang百万级高并发实例

前言 感谢Handling 1 Million Requests per Minute with Go 这篇文章给予的巨大启发。 基础 我们使用Go语言,基本上是因为他原生支持的高并发:Goroutine 和 Channel; Go 的并发属于 CSP 并...

wz669
2019/01/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何获取NuGet以安装/更新packages.config中的所有软件包?

问题: I have a solution with multiple projects in it. 我有一个包含多个项目的解决方案。 Most of the third party references are missing, yet there are packages.config file for e......

fyin1314
32分钟前
17
0
Xcode中的版本与版本 - Version vs build in Xcode

问题: I have an app that I developed with Xcode 3 and recently started editing with Xcode 4. In the target summary I have the iOS application target form with fields: identifie......

javail
今天
14
0
如何在Python中将字典键作为列表返回? - How to return dictionary keys as a list in Python?

问题: In Python 2.7 , I could get dictionary keys , values , or items as a list: 在Python 2.7中 ,我可以将字典键 , 值或项作为列表获取: >>> newdict = {1:0, 2:0, 3:0}>>> newd......

技术盛宴
今天
17
0
2020世界人工智能大会开幕首日 百度与浦发银行达成战略合作

本文作者:y****n 7月9日,2020世界人工智能大会开幕首日,百度与浦发银行签署战略合作协议,将在人工智能、金融科技等多个领域进一步深化合作。双方将优势互补,实现人工智能技术在金融领域...

百度开发者中心
昨天
26
0
Java中C ++ Pair 的等价物是什么? - What is the equivalent of the C++ Pair in Java?

问题: Is there a good reason why there is no Pair<L,R> in Java? 有没有一个很好的理由说明Java中没有Pair<L,R> ? What would be the equivalent of this C++ construct? 这个C ++构造的......

富含淀粉
今天
18
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部