##思路讲解
- 开辟几个固定的协程可供调度,这个大小也是可以指定的
- channel的作用,用于唤醒协程处理并发关系
- 协程执行的函数结构的存储问题
###threadPool的数据结构
type ThreadPool struct {
ch chan int /*channel*/
size int
threadNum int
tasks *list.List /*list容器,需要这样定义变量*/
}
###函数的保存
task函数需要保存在list当中,但是list我第一次用感觉还是很奇葩的。我看了很多关于list的帖子感觉没讲明白。
####List的使用
go的list的封装很有趣,list里面包含了两部分内容
- list.Element 对于存储的数据结构封装(接口)可以看到其实就是个接口罢了,很方便。所有获取元素的方法,比如Front之类的返回的都是Element类型的,所以我们需要调用Value来获得实际上的存储内容。
//container/list––––––––––––––container/list_
type Element struct {
Value interface{} // 存储在该元素中的值
}
- list.List 存储方式 (链表本身)
定义一个list的方法,第二种适合在结构体里面使用
myList := list.New()
var myList list.List
####使用反射技术存储函数和参数
这里主要是参考这篇文章:
//我们就是用这个结构体存储函数的,要是c++11的话就是std::function
type CallAble struct {
f reflect.Value //存储函数
args []reflect.Value //存储参数
}
//我记得c++11里面也有arg...的用法,不过是用模板,太麻烦
func (this* ThreadPool) Add(f interface{},args... interface{}) {
var task CallAble ;
//保存函数指针??
task.f = reflect.ValueOf( f );
t := task.f.Type() //判断一下存储的是不是函数
if t.Kind() == reflect.Func {
task.args = make([]reflect.Value , len(args) )
for i := 0 ; i < len(args) ; i ++ {
//保存函数的参数
task.args[i] = reflect.ValueOf(args[i])
}
this.tasks.PushBack(task)
}
}
//函数调用
//截取片段 ——————————————————————————————
if(this.tasks.Len() != 0) {
e := this.tasks.Front() //返回的是element
task ,_:= e.Value.(CallAble) //获得element里面存储的callable
task.f.Call(task.args) // 调用函数
this.tasks.Remove(e)
}
###全部代码
package ThreadPool
import (
"fmt"
"reflect"
"container/list"
)
type ThreadPool struct {
ch chan int
size int
threadNum int
tasks *list.List
}
type CallAble struct {
f reflect.Value //存储函数
args []reflect.Value //存储参数
}
//线程池就是池子里面有几个进程,当进程不够的时候自己去开辟新的线程
//如果执行完毕之后再把这个线程清掉
//Init 函数
func (this* ThreadPool) Init(size int) {
this.ch = make(chan int)
this.size = size
this.tasks = list.New()
this.threadNum = 0;
//先初始化几个process
for i := 0 ; i < size ; i++ {
go this.process()
}
}
func (this* ThreadPool) Add(f interface{},args... interface{}) {
var task CallAble ;
task.f = reflect.ValueOf( f );
t := task.f.Type()
if t.Kind() == reflect.Func {
task.args = make([]reflect.Value , len(args) )
for i := 0 ; i < len(args) ; i ++ {
task.args[i] = reflect.ValueOf(args[i])
}
this.tasks.PushBack(task)
}
//每次添加一个task判断一下是否需要开新的task
//不过应该不需要,因为chan封装了队列,只是个人尝试
if(this.threadNum >= this.size) {
go this.process()
}else {
//一定要在协程里面使用chan,我老把主线程锁掉
go func(){
this.ch <- 1
}()
}
}
func (this* ThreadPool) process() {
for {
<- this.ch
fmt.Printf("threadNum is %d \n" ,this.threadNum)
this.threadNum ++ //当前进程在忙
if(this.tasks.Len() != 0) {
e := this.tasks.Front()
task ,_:= e.Value.(CallAble)
task.f.Call(task.args)
this.tasks.Remove(e)
}
//如果当前的的routine数量多了就退出
if(this.threadNum >= this.size - 1){
fmt.Println("exit \n" ,this.threadNum)
this.threadNum --
break
} else {
this.threadNum --//又空闲了一个进程
}
}
}
不写不知道,一写吓一跳,感觉就是还应该增加一下waitGroup的内容,这样主线程在使用的时候会等待所有的协程结束。