zoukankan      html  css  js  c++  java
  • golang限制协程的最大开启数

    package main
    
    import (
    	"fmt"
    	"strconv"
    	"time"
    )
    
    var (
    	maxRoutineNum = 2
    )
    
    // 模拟下载页面的方法
    func download(url string, ch chan int) {
    	fmt.Println("download from ", url)
    	// 休眠两秒模拟下载页面
    	time.Sleep(2 * 1e9)
    	// 下载完成则从ch推出数据
    	i :=<-ch
    	fmt.Println(i)
    }
    
    func main() {
    	ch := make(chan int, maxRoutineNum)
    
    	urls := [10]string{}
    	for i := 0; i < 10; i++ {
    		urls[i] = "url" + strconv.Itoa(i)
    	}
    	for i := 0; i < len(urls); i++ {
    		// 开启下载协程前往ch塞一个数据
    		// 如果ch满了则会处于阻塞,从而达到限制最大协程的功能
    
    		go download(urls[i], ch)
    		ch <- 1  //放在后面是三个 放在下载之前,是两个并发
    	}
    
    
    }
    

      

    虽然golang中协程开销很低,但是在一些情况下还是有必要限制一下协程的开启数,比如爬虫中的下载协程,因为受到带宽限制,开的多了也没有效果。本来想在网上找找有没协程池,类似其它语言线程池这样的东西,可以限制最大开启数。找了一番,这方面的资料非常少,难道golang不需要协程池这种东东?自己动手写一个吧。

    要限制协程最大数量,就是考虑开启一个协程的时候记录一下,然后超过最大数就不再开启。可以考虑用一个变量count来记录协程开启数量,不过这种方式比较out了,golang中可以用channel来实现。

    不限制的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    package main
     
    import (
        "fmt"
        "strconv"
        "time"
    )
     
    // 模拟下载页面的方法
    func download(url string) {
        fmt.Println("download from ", url)
    }
     
    func main() {
        urls := [100]string{}
        for i := 0; i < 100; i++ {
            urls[i] = "url" + strconv.Itoa(i)
        }
        for i := 0; i < len(urls); i++ {
            go download(urls[i])
        }
     
        // 休眠一下
        for {
            time.Sleep(1 1e9)
        }
    }

    根据url数量开启若干协程,每个协程会去下载页面内容,通常受到带宽的限制,协程开多了没有什么提升效果。

    限制一下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    package main
     
    import (
        "fmt"
        "strconv"
        "time"
    )
     
    var (
        maxRoutineNum = 10
    )
     
    // 模拟下载页面的方法
    func download(url string, ch chan int) {
        fmt.Println("download from ", url)
        // 休眠两秒模拟下载页面
        time.Sleep(2 1e9)
        // 下载完成则从ch推出数据
        <-ch
    }
     
    func main() {
        ch := make(chan int, maxRoutineNum)
     
        urls := [100]string{}
        for i := 0; i < 100; i++ {
            urls[i] = "url" + strconv.Itoa(i)
        }
        for i := 0; i < len(urls); i++ {
            // 开启下载协程前往ch塞一个数据
            // 如果ch满了则会处于阻塞,从而达到限制最大协程的功能
            ch <- 1
            go download(urls[i], ch)
        }
     
        // 休眠一下
        for {
            time.Sleep(1 1e9)
        }
    }

    主要就是用golang中channel的阻塞性和最大数量处理,可以考虑封装一下提供使用。

    golang真的不需要协程池?

  • 相关阅读:
    解决:Failed to update database: "APP_DATA\ASPNETDB.MDF" is readonly .
    MySQL DATE_ADD() 函数
    用struts上传图片,中文命名的图片无法显示
    hrbustoj 1291 点在凸多边形内
    按标签来查技术文章
    ClassLoader in Java
    [Python]标准库inspect
    IMEI修改(IMEI第十五位验证码的计算)
    游戏之巅:游戏背后的创业风云
    常用的网站后台编辑器
  • 原文地址:https://www.cnblogs.com/brady-wang/p/14308783.html
Copyright © 2011-2022 走看看