go语言实现线程池

时间:2024-01-11 15:51:56

话说真的好久没有写博客了,最近赶新项目,工作太忙了。这一周任务比较少,又可以随便敲敲了。

逛论坛的时候突发奇想,想用go语言实现一个线程池,主要功能是:添加total个任务到线程池中,线程池开启number个线程,每个线程从任务队列中取出一个任务执行,执行完成后取下一个任务,全部执行完成后回调一个函数。

不知道有没有卵用,但是我尝试用它开启3个线程,下载10个文件,效果还是不错的。第一次写这方面的东西,可能写得不好。

思路就是把任务放到channel里,每个线程不停的从channel中取出任务执行,并把执行结果写入另一个channel,当得到total个结果后,回调函数。

上一发代码:

 type GoroutinePool struct {
Queue chan func() error
Number int
Total int result chan error
finishCallback func()
} // 初始化
func (self *GoroutinePool) Init(number int, total int) {
self.Queue = make(chan func() error, total)
self.Number = number
self.Total = total
self.result = make(chan error, total)
} // 开门接客
func (self *GoroutinePool) Start() {
// 开启Number个goroutine
for i := ; i < self.Number; i++ {
go func() {
for {
task, ok := <-self.Queue
if !ok {
break
} err := task()
self.result <- err
}
}()
} // 获得每个work的执行结果
for j := ; j < self.Total; j++ {
res, ok := <-self.result
if !ok {
break
} if res != nil {
fmt.Println(res)
}
} // 所有任务都执行完成,回调函数
if self.finishCallback != nil {
self.finishCallback()
}
} // 关门送客
func (self *GoroutinePool) Stop() {
close(self.Queue)
close(self.result)
} // 添加任务
func (self *GoroutinePool) AddTask(task func() error) {
self.Queue <- task
} // 设置结束回调
func (self *GoroutinePool) SetFinishCallback(callback func()) {
self.finishCallback = callback
}

开启3个线程,下载10个文件的测试代码:

 func Download_test() {
urls := []string{
"http://dlsw.baidu.com/sw-search-sp/soft/44/17448/Baidusd_Setup_4.2.0.7666.1436769697.exe",
"http://dlsw.baidu.com/sw-search-sp/soft/3a/12350/QQ_V7.4.15197.0_setup.1436951158.exe",
"http://dlsw.baidu.com/sw-search-sp/soft/9d/14744/ChromeStandalone_V43.0.2357.134_Setup.1436927123.exe",
"http://dlsw.baidu.com/sw-search-sp/soft/6f/15752/iTunes_V12.2.1.16_Setup.1436855012.exe",
"http://dlsw.baidu.com/sw-search-sp/soft/70/17456/BaiduAn_Setup_5.0.0.6747.1435912002.exe",
"http://dlsw.baidu.com/sw-search-sp/soft/40/12856/QIYImedia_1_06_v4.0.0.32.1437470004.exe",
"http://dlsw.baidu.com/sw-search-sp/soft/42/37473/BaiduSoftMgr_Setup_7.0.0.1274.1436770136.exe",
"http://dlsw.baidu.com/sw-search-sp/soft/49/16988/YoudaoNote_V4.1.0.300_setup.1429669613.exe",
"http://dlsw.baidu.com/sw-search-sp/soft/55/11339/bdbrowserSetup-7.6.100.2089-1212_11000003.1437029629.exe",
"http://dlsw.baidu.com/sw-search-sp/soft/53/21734/91zhushoupc_Windows_V5.7.0.1633.1436844901.exe",
} pool := new(GoroutinePool)
pool.Init(, len(urls)) for i := range urls {
url := urls[i]
pool.AddTask(func() error {
return download(url)
})
} isFinish := false pool.SetFinishCallback(func() {
func(isFinish *bool) {
*isFinish = true
}(&isFinish)
}) pool.Start() for !isFinish {
time.Sleep(time.Millisecond * )
} pool.Stop()
fmt.Println("所有操作已完成!")
} func download(url string) error {
fmt.Println("开始下载... ", url) sp := strings.Split(url, "/")
filename := sp[len(sp)-] file, err := os.Create("/Users/staff/Documents/Red_Test/AAAA/" + filename)
if err != nil {
return err
} res, err := http.Get(url)
if err != nil {
return err
} length, err := io.Copy(file, res.Body)
if err != nil {
return err
} fmt.Println("## 下载完成! ", url, " 文件长度:", length)
return nil
}

使用起来还算可以的吧。。。