Go并发之百万级处理
代码和注释均在代码:
package main
import (
"fmt"
"runtime"
"time"
)
//---------------------Job-------------------------
type Job interface {
Do()
}
// 一个数据接口,所有的数据都要实现该接口,才能被传递进来
//实现Job接口的一个数据实例,需要实现一个Do()方法,对数据的处理就在这个Do()方法中。
/*
Job通道:
这里有两个Job通道:
1、WorkerPool的Job channel,用于调用者把具体的数据写入到这里,WorkerPool读取。
2、Worker的Job channel,当WorkerPool读取到Job,并拿到可用的Worker的时候,会将Job实例写入该Worker的Job channel,用来直接执行Do()方法。
*/
//--------------------Worker-----------------------
type Worker struct {
JobQueue chan Job //Worker的Job通道
}
func NewWorker() Worker {
return Worker{JobQueue: make(chan Job)}
}
//每一个被初始化的worker都会在后期单独占用一个协程
//初始化的时候会先把自己的JobQueue传递到Worker通道中,
//然后阻塞读取自己的JobQueue,读到一个Job就执行Job对象的Do()方法。
func (w Worker) Run(wq chan chan Job) {
go func() {
for{
wq <- w.JobQueue
select {
case job := <- w.JobQueue:
job.Do()
}
}
}()
}
//----------------WorkerPool---------------------
//工作池(WorkerPool):
type WorkerPool struct {
workerlen int //WorkerPool中同时 存在Worker的个数
JobQueue chan Job // WorkerPool的Job通道
WorkerQueue chan chan Job
}
//初始化时会按照传入的num,启动num个后台协程,然后循环读取Job通道里面的数据,
//读到一个数据时,再获取一个可用的Worker,并将Job对象传递到该Worker的chan通道
func NewWorkerPool(workerlen int) *WorkerPool {
return &WorkerPool{
workerlen: workerlen,
JobQueue: make(chan Job),
WorkerQueue: make(chan chan Job,workerlen),
}
}
func (wp *WorkerPool) Run() {
fmt.Println("初始化worker...")
for i:=0;i<wp.workerlen;i++ {
worker := NewWorker()
worker.Run(wp.WorkerQueue)
}
go func() {
for{
select {
case job := <-wp.JobQueue:
worker :=<-wp.WorkerQueue
worker <- job
}
}
}()
}
//------------------测试--------------------
type Score struct {
Num int
}
func (s *Score) Do() {
fmt.Println("num:",s.Num)
time.Sleep(time.Second*1*1)
}
func main() {
num := 100*100*20
p := NewWorkerPool(num)
p.Run()
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(time.Second*2)
}
}

浙公网安备 33010602011771号