参考:https://blog.csdn.net/Jeanphorn/article/details/79018205
感谢Handling 1 Million Requests per Minute with Go这篇文章给予的巨大启发。
workerpool.go
package main
import "fmt"
type Job interface {
Do()
}
type Worker struct {
JobQueue chan Job
}
func NewWorker() Worker {
return Worker{JobQueue: make(chan Job)}
}
func (w Worker) Run(wq chan chan Job) {
go func() {
for {
wq <- w.JobQueue
select {
case job := <-w.JobQueue:
job.Do()
}
}
}()
}
// ---------------------------------------------------------
type WorkerPool struct {
workerlen int
JobQueue chan Job
WorkerQueue chan chan Job
}
func NewWorkerPool(workerlen, joblen int) *WorkerPool {
return &WorkerPool{
workerlen: workerlen,
JobQueue: make(chan Job, joblen),
WorkerQueue: make(chan chan Job, workerlen),
}
}
func (wp *WorkerPool) Start() {
fmt.Println("初始化worker")
//初始化worker
for i := 0; i < wp.workerlen; i++ {
worker := NewWorker()
worker.Run(wp.WorkerQueue)
}
// 循环获取可用的worker,往worker中写job
go func() {
for {
select {
case job := <-wp.JobQueue:
worker := <-wp.WorkerQueue
worker <- job
}
}
}()
}
// ------------------------
/*
func main() {
workernum := 100 * 100
jobnum := 100 * 100 * 20
// debug.SetMaxThreads(num + 1000) //设置最大线程数
// 注册工作池,传入任务
// 参数1 worker并发个数
p := NewWorkerPool(workernum, jobnum)
p.Start()
datanum := 100 * 100 * 100 * 100
go func() {
for i := 1; i <= datanum; i++ {
sc := &Score{Num: i}
p.JobQueue <- sc
}
}()
for {
fmt.Println("runtime.NumGoroutine() :", runtime.NumGoroutine())
time.Sleep(2 * time.Second)
}
}
*/
main.go
package main
import (
"fmt"
"runtime"
"time"
)
type Score struct {
Num int
}
func (s *Score) Do() {
fmt.Println("num:", s.Num)
time.Sleep(1 * 10 * time.Second)
}
func main() {
workernum := 100 * 100
jobnum := 100 * 100 * 20
// debug.SetMaxThreads(num + 1000) //设置最大线程数
// 注册工作池,传入任务
// 参数1 worker并发个数
p := NewWorkerPool(workernum, jobnum)
p.Start()
datanum := 100 * 100 * 100 * 100
go func() {
for i := 1; i <= datanum; i++ {
sc := &Score{Num: i}
p.JobQueue <- sc
}
}()
for {
fmt.Println("runtime.NumGoroutine() :", runtime.NumGoroutine())
time.Sleep(2 * time.Second)
}
}
_test.go
package main
import (
"strings"
"testing"
)
// go test -run=xxx -bench=. -benchtime="3s" -cpuprofile profile_cpu.out
/*
https://graphviz.gitlab.io/_pages/Download/Download_windows.html
# go tool pprof -svg profile_cpu.out > profile_cpu.svg
# go tool pprof -pdf profile_cpu.out > profile_cpu.pdf
*/
func BenchmarkStringJoin1(b *testing.B) {
// 在report中包含内存分配信息 BenchmarkStringJoin1-4 300000 4351 ns/op 32 B/op 2 allocs/op
/*
-4表示4个CPU线程执行;
300000表示总共执行了30万次;
4531ns/op,表示每次执行耗时4531纳秒;
32B/op表示每次执行分配了32字节内存;
2 allocs/op表示每次执行分配了2次对象。
*/
b.ReportAllocs()
input := []string{"Hello", "World"}
for i := 0; i < b.N; i++ {
result := strings.Join(input, " ")
if result != "Hello World" {
b.Error("Unexpected result: " + result)
}
}
}
func BenchmarkStringJoin2(b *testing.B) {
b.ReportAllocs()
input := []string{"Hello", "World"}
join := func(strs []string, delim string) string {
if len(strs) == 2 {
return strs[0] + delim + strs[1]
}
return ""
}
for i := 0; i < b.N; i++ {
result := join(input, " ")
if result != "Hello World" {
b.Error("Unexpected result: " + result)
}
}
}
func BenchmarkStringJoin2B(b *testing.B) {
b.ReportAllocs()
join := func(strs []string, delim string) string {
if len(strs) == 2 {
return strs[0] + delim + strs[1]
}
return ""
}
for i := 0; i < b.N; i++ {
input := []string{"Hello", "World"}
result := join(input, " ")
if result != "Hello World" {
b.Error("Unexpected result: " + result)
}
}
}
/*
只关心性能最差的那个
go test -run=xxx -bench=BenchmarkStringJoin2B$ -cpuprofile profile_2b.out
go test -run=xxx -bench=BenchmarkStringJoin2$ -cpuprofile profile_2.out
go tool pprof -svg profile_2b.out > profile_2b.svg
go tool pprof -svg profile_2.out > profile_2.svg
*/