DisruptorLinkedBlockingQueue
channel
测试场景设计的思路与前两篇文章相同,通过三个场景对变量的修改进行对比压测,包括不限于数量、大小、goroutine的数量。
结论
channel
fasthttp.Requestnet/http.Request
简介
Go 语言中的通道(channel)是一种特殊的类型。通道像一个传送带或者队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。每一个通道都是一个具体类型的导管,也就是声明channel的时候需要为其指定元素类型。如果说goroutine是Go程序并发的执行体,channel就是它们之间的连接。channel是可以让一个goroutine发送特定值到另一个goroutine的通信机制。
channelchannel
测试结果
Disruptor
数据说明
net/httpRequest
小对象:
get, _ := http.NewRequest("GET", base.Empty, nil)
中对象:
get,_ := http.NewRequest("GET",base.Empty, nil)
get.Header.Add("token", token)
get.Header.Add("Connection", base.Connection_Alive)
get.Header.Add("User-Agent", base.UserAgent)
大对象:
get,_ := http.NewRequest("GET",base.Empty, nil)
get.Header.Add("token", token)
get.Header.Add("token1", token)
get.Header.Add("token2", token)
get.Header.Add("token3", token)
get.Header.Add("token4", token)
get.Header.Add("token5", token)
get.Header.Add("Connection", base.Connection_Alive)
get.Header.Add("User-Agent", base.UserAgent)
生产者
对象大小 | 队列长度 (百万) | 线程数 | 速率(/ms) |
---|
net/httpRequest
- 长度在50万 ~ 1000万没有明显差异
- 生产者越多越好(20以内,再多增益效果不明显)
- 消息体尽可能小
消费者
对象大小 | 队列长度 (百万) | 线程数 | 速率(/ms) |
---|
net/httpRequest
- 长度在50万 ~ 500万没有明显差异
- 消费者10 ~ 20以内到达峰值
- 消息体尽可能小
Disruptor
生产者 & 消费者
这里的线程数指的是生产者或者消费者的数量,总体线程数是此数值的2倍。
对象大小 | 次数 (百万) | 线程数 | 速率(/ms) |
---|
net/httpRequest
- 消息队列积累消息对性能影响不大
- 消费次数越多,性能反而有点下降,应该是生产者速率不足导致
- 消息体尽可能小,不过性能下降不多
测试用例
总体代码逻辑与Java和Groovy用例一样,有几处差别如下:
sync.WaitGroupjava.util.concurrent.CountDownLatchjava.util.concurrent.CyclicBarrier
GochannelsizeLinkedBlockingQueue
atomic.AddInt32
生产者场景
func TestQueue(t *testing.T) {
var index int32 = 0
rs := make(chan *http.Request, total+10000)
var group sync.WaitGroup
group.Add(threadNum)
milli := futil.Milli()
funtester := func() {
go func() {
for {
l := atomic.AddInt32(&index, 1)
if l%piece == 0 {
m := futil.Milli()
log.Println(m - milli)
milli = m
}
if l > total {
break
}
get := getRequest()
rs <- get
}
group.Done()
}()
}
start := futil.Milli()
for i := 0; i < threadNum; i++ {
funtester()
}
group.Wait()
end := futil.Milli()
log.Println(atomic.LoadInt32(&index))
log.Printf("平均每毫秒速率%d", total/(end-start))
}
消费者场景
生产者 & 消费者 场景
这里我引入了另外一个变量:初始队列长度length,用例运行之前将队列按照这个长度进行单线程填充。
func TestConsumer(t *testing.T) {
rs := make(chan *http.Request, total+10000)
var group sync.WaitGroup
group.Add(10)
funtester := func() {
go func() {
for {
if len(rs) > total {
break
}
get := getRequest()
rs <- get
}
group.Done()
}()
}
for i := 0; i < 10; i++ {
funtester()
}
group.Wait()
log.Printf("造数据完成! 总数%d", len(rs))
totalActual := int64(len(rs))
var conwait sync.WaitGroup
conwait.Add(threadNum)
consumer := func() {
go func() {
FUN:
for {
select {
case <-rs:
case <-time.After(10 * time.Millisecond):
break FUN
}
}
conwait.Done()
}()
}
start := futil.Milli()
for i := 0; i < threadNum; i++ {
consumer()
}
conwait.Wait()
end := futil.Milli()
log.Printf("平均每毫秒速率%d", totalActual/(end-start))
}
生产对象
func getRequest() *http.Request {
//get, _ := http.NewRequest("GET", base.Empty, nil)
//get,_ := http.NewRequest("GET",url, nil)
//get.Header.Add("token", token)
//get.Header.Add("Connection", base.Connection_Alive)
//get.Header.Add("User-Agent", base.UserAgent)
get,_ := http.NewRequest("GET",url, nil)
get.Header.Add("token", token)
get.Header.Add("token1", token)
get.Header.Add("token2", token)
get.Header.Add("token3", token)
get.Header.Add("token4", token)
get.Header.Add("token5", token)
get.Header.Add("Connection", base.Connection_Alive)
get.Header.Add("User-Agent", base.UserAgent)
return get
}
补充
性能非常不稳定
java.util.concurrent.LinkedBlockingQueue
基准测试
net/http
测试对象 | 线程数 | 个数(百万) | 速率(/ms) |
---|
fasthttp.Request
测试对象 | 线程数 | 个数(百万) | 速率(/ms) |
---|
fasthttp.Requestnet/http.Request
测试用例如下:
// TestBase
// @Description: 基准测试
// @param t
func TestBase(t *testing.T) {
execute.ExecuteRoutineTimes(func() {
getRequest()
},total,threadNum)
}