• go语言实现线程池


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

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

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

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

    上一发代码:

     1 type GoroutinePool struct {
     2     Queue  chan func() error
     3     Number int
     4     Total  int
     5 
     6     result         chan error
     7     finishCallback func()
     8 }
     9 
    10 // 初始化
    11 func (self *GoroutinePool) Init(number int, total int) {
    12     self.Queue = make(chan func() error, total)
    13     self.Number = number
    14     self.Total = total
    15     self.result = make(chan error, total)
    16 }
    17 
    18 // 开门接客
    19 func (self *GoroutinePool) Start() {
    20     // 开启Number个goroutine
    21     for i := 0; i < self.Number; i++ {
    22         go func() {
    23             for {
    24                 task, ok := <-self.Queue
    25                 if !ok {
    26                     break
    27                 }
    28 
    29                 err := task()
    30                 self.result <- err
    31             }
    32         }()
    33     }
    34 
    35     // 获得每个work的执行结果
    36     for j := 0; j < self.Total; j++ {
    37         res, ok := <-self.result
    38         if !ok {
    39             break
    40         }
    41 
    42         if res != nil {
    43             fmt.Println(res)
    44         }
    45     }
    46 
    47     // 所有任务都执行完成,回调函数
    48     if self.finishCallback != nil {
    49         self.finishCallback()
    50     }
    51 }
    52 
    53 // 关门送客
    54 func (self *GoroutinePool) Stop() {
    55     close(self.Queue)
    56     close(self.result)
    57 }
    58 
    59 // 添加任务
    60 func (self *GoroutinePool) AddTask(task func() error) {
    61     self.Queue <- task
    62 }
    63 
    64 // 设置结束回调
    65 func (self *GoroutinePool) SetFinishCallback(callback func()) {
    66     self.finishCallback = callback
    67 }

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

     1 func Download_test() {
     2     urls := []string{
     3         "http://dlsw.baidu.com/sw-search-sp/soft/44/17448/Baidusd_Setup_4.2.0.7666.1436769697.exe",
     4         "http://dlsw.baidu.com/sw-search-sp/soft/3a/12350/QQ_V7.4.15197.0_setup.1436951158.exe",
     5         "http://dlsw.baidu.com/sw-search-sp/soft/9d/14744/ChromeStandalone_V43.0.2357.134_Setup.1436927123.exe",
     6         "http://dlsw.baidu.com/sw-search-sp/soft/6f/15752/iTunes_V12.2.1.16_Setup.1436855012.exe",
     7         "http://dlsw.baidu.com/sw-search-sp/soft/70/17456/BaiduAn_Setup_5.0.0.6747.1435912002.exe",
     8         "http://dlsw.baidu.com/sw-search-sp/soft/40/12856/QIYImedia_1_06_v4.0.0.32.1437470004.exe",
     9         "http://dlsw.baidu.com/sw-search-sp/soft/42/37473/BaiduSoftMgr_Setup_7.0.0.1274.1436770136.exe",
    10         "http://dlsw.baidu.com/sw-search-sp/soft/49/16988/YoudaoNote_V4.1.0.300_setup.1429669613.exe",
    11         "http://dlsw.baidu.com/sw-search-sp/soft/55/11339/bdbrowserSetup-7.6.100.2089-1212_11000003.1437029629.exe",
    12         "http://dlsw.baidu.com/sw-search-sp/soft/53/21734/91zhushoupc_Windows_V5.7.0.1633.1436844901.exe",
    13     }
    14 
    15     pool := new(GoroutinePool)
    16     pool.Init(3, len(urls))
    17 
    18     for i := range urls {
    19         url := urls[i]
    20         pool.AddTask(func() error {
    21             return download(url)
    22         })
    23     }
    24 
    25     isFinish := false
    26 
    27     pool.SetFinishCallback(func() {
    28         func(isFinish *bool) {
    29             *isFinish = true
    30         }(&isFinish)
    31     })
    32 
    33     pool.Start()
    34 
    35     for !isFinish {
    36         time.Sleep(time.Millisecond * 100)
    37     }
    38 
    39     pool.Stop()
    40     fmt.Println("所有操作已完成!")
    41 }
    42 
    43 func download(url string) error {
    44     fmt.Println("开始下载... ", url)
    45 
    46     sp := strings.Split(url, "/")
    47     filename := sp[len(sp)-1]
    48 
    49     file, err := os.Create("/Users/staff/Documents/Red_Test/AAAA/" + filename)
    50     if err != nil {
    51         return err
    52     }
    53 
    54     res, err := http.Get(url)
    55     if err != nil {
    56         return err
    57     }
    58 
    59     length, err := io.Copy(file, res.Body)
    60     if err != nil {
    61         return err
    62     }
    63 
    64     fmt.Println("## 下载完成! ", url, " 文件长度:", length)
    65     return nil
    66 }

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

  • 相关阅读:
    UVALive 5966 Blade and Sword -- 搜索(中等题)
    UVA 12380 Glimmr in Distress --DFS
    【转】最长回文子串的O(n)的Manacher算法
    UVA 12382 Grid of Lamps --贪心+优先队列
    UVA 12377 Number Coding --DFS
    高斯消元模板
    图的全局最小割的Stoer-Wagner算法及例题
    逻辑运算符短路特性的应用
    为什么在 Java 中用 (low+high)>>>1 代替 (low+high)/2 或 (low+high)>>1 来计算平均值呢?好在哪里?
    数据库读写分离和数据一致性的冲突
  • 原文地址:https://www.cnblogs.com/wolfred7464/p/4667604.html
Copyright © 2020-2023  润新知