通过 Channel 实现 Goroutine Pool
最近用到了 Go 从 Excel 导数据到服务器内部 用的是 http 请求
但是发现一个问题 从文件读取之后 新开 Goroutine 会无限制新增
导致全部卡在初始化请求 于是乎就卡死了
问题模拟
- 模拟代码
func main() {
pool := sync.WaitGroup{}
for i := 0; i < 500; i++ {
pool.Add(1)
go func(i int) {
resp, err := http.Get("http://ip.3322.org")
if err != nil {
fmt.Println(i, err)
} else {
defer resp.Body.Close()
result, _ := ioutil.ReadAll(resp.Body)
fmt.Println(i, string(result))
}
pool.Done()
}(i)
}
pool.Wait()
}
- 数量小的情况下 没有问题 但是数量比较大的情况 就会发现程序直接卡死 一段时间之后报错 并且没有发出任何请求
问题解决
- 实际上看的出来 是应为同时发起了太多的HTTP请求 导致系统卡死 数据没有发送
- 想到我在Java中用Thread提交请求 我就考虑 可不可限制 Goroutine 的数量
- 使用强大的百度 果然找到了大佬已经写好的协程池
- 代码如下 我加上了注释
package gopool
import (
"sync"
)
// Pool Goroutine Pool
type Pool struct {
queue chan int
wg *sync.WaitGroup
}
// New 新建一个协程池
func New(size int) *Pool {
if size <= 0 {
size = 1
}
return &Pool{
queue: make(chan int, size),
wg: &sync.WaitGroup{},
}
}
// Add 新增一个执行
func (p *Pool) Add(delta int) {
// delta为正数就添加
for i := 0; i < delta; i++ {
p.queue <- 1
}
// delta为负数就减少
for i := 0; i > delta; i-- {
<-p.queue
}
p.wg.Add(delta)
}
// Done 执行完成减一
func (p *Pool) Done() {
<-p.queue
p.wg.Done()
}
// Wait 等待Goroutine执行完毕
func (p *Pool) Wait() {
p.wg.Wait()
}
- 然后修改刚才的测试方法
package main
import (
"io/ioutil"
"log"
"net/http"
"yumc.pw/cloud/lib/gopool"
)
func main() {
// 这里限制5个并发
pool := gopool.New(5)// sync.WaitGroup{}
for i := 0; i < 500; i++ {
pool.Add(1)
go func(i int) {
resp, err := http.Get("http://ip.3322.org")
if err != nil {
fmt.Println(i, err)
} else {
defer resp.Body.Close()
result, _ := ioutil.ReadAll(resp.Body)
fmt.Println(i, string(result))
}
pool.Done()
}(i)
}
pool.Wait()
}
- 完美解决
通过 Channel 实现 Goroutine Pool的更多相关文章
- 如果裸写一个goroutine pool
引言 在上文中,我说到golang的原生http server处理client的connection的时候,每个connection起一个goroutine,这是一个相当粗暴的方法.为了感受更深一点, ...
- fasthttp 的 goroutine pool 实现探究
引言 fasthttp是一个非常优秀的web server框架,号称比官方的net/http快10倍以上.fasthttp用了很多黑魔法.俗话说,源码面前,了无秘密,我们今天通过源码来看一看她的gor ...
- goroutine pool,WaitGroup,chan 示例
服务端高并发编程经常需要写很多goroutine来服务每一个连接,如何正确使用goroutine池是又拍云的工程师们需要考虑的问题,今天这篇文章,分享给同样需要使用go语言的小伙伴们. 文/陶克路 本 ...
- golang 部分理解:关于channel 和 goroutine 例子
部分理解:关于channel 和 goroutine 例子package main import "strconv" import "fmt" func mai ...
- golang(8):channel读写 & goroutine 通信
goroutine 1.进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位 B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独 ...
- golang如何使用channel控制goroutine退出
最经典的处理方式: 在启动goroutine的时候,传递一个额外的chan型参数,用来接收退出信号,代码如下 func worker(name string, stopchan chan struct ...
- TODO:Go语言goroutine和channel使用
TODO:Go语言goroutine和channel使用 goroutine是Go语言中的轻量级线程实现,由Go语言运行时(runtime)管理.使用的时候在函数前面加"go"这个 ...
- Go语言学习笔记(七)杀手锏 Goroutine + Channel
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 Goroutine Go语言的主要的功能在于令人简易使用的并行设计,这个方法叫做Goroutine,通过Gorou ...
- go语言之行--golang核武器goroutine调度原理、channel详解
一.goroutine简介 goroutine是go语言中最为NB的设计,也是其魅力所在,goroutine的本质是协程,是实现并行计算的核心.goroutine使用方式非常的简单,只需使用go关键字 ...
随机推荐
- 洛谷P3905 道路重建
题目:https://www.luogu.org/problemnew/show/P3905 分析: 此题是显然的最短路算法,只是看到一起删掉的一堆边感到十分棘手,而且还要求出的是最短添加边的总长度 ...
- Netty-解码器架构与常用解码器
任何数据类型想在网络中进行传输,都得经过编解码转换成字节流 在netty中,服务端和客户端进行通信的其实是下面这样的 程序 ---编码--> 网络 网路 ---解码--> 程序 对应服务端 ...
- Gym - 101194L World Cup 暴力
World CupInput file: Standard InputOutput file: Standard OuptutTime limit: 1 second Here is World Cu ...
- e校帮V1.1使用指南
2017年04月17日,e校帮正式版本V1.1.4正式上线了.大家可以在e校帮官网进行下载,http://exiaobang.top 或者在搜狗手机助手/搜狗输入法/酷安进行下载. e校帮简介: e校 ...
- [leetcode] 309. Best Time to Buy and Sell Stock with Cooldown(medium)
原题 思路: 状态转移 出售股票的状态,最大利润有两种可能. 一,和昨天一样不动:二,昨天持有的股票今天卖掉. sell[i] = max(sell[i-1],buy[i-1] + prices[i] ...
- 微信小程序踩坑日记1——调用微信授权窗口
0. 引言 微信小程序为了优化用户体验,取消了在进入小程序时立马出现授权窗口.需要用户主动点击按钮,触发授权窗口. 那么,在我实践过程中,出现了以下问题. . 无法弹出授权窗口 . 希望在用户已经授权 ...
- python中的元类(metaclass)
认识python中元类的准备工作. 1,首先需要明白一个概念就是python中一切皆为对象. input: class Trick(object): pass ') print type(1234) ...
- CSS和html如何结合起来——选择符及优先级
1.选择符 兼容性 统配选择符 * 元素选择符 body 类选择符 .class id选择符 #id 包含原则符 p strong (所有 ...
- 【iOS】iOS Error Domain=NSCocoaErrorDomain Code=3840 "未能完成操作。(“Cocoa”错误 3840。)"
昨天遇到的这个问题,详细信息: ----->类和方法__25+[Manager noticeRequest:]_block_invoke399----->错误信息Error Domain= ...
- gdb调试和编译后运行结果不一致
今天在看代码时,遇到这么一段代码,我但是用g++编译了,运行发现有Segmentation fault. 然后就用gdb跟进去看看,可是gdb却正常执行了.不知道什么原因. #include < ...