Go 语言从入门到实战
蔡超
Mobvista 技术副总裁兼首席架构师,前亚马逊(中国)首席软件架构师
48919 人已学习
新⼈⾸单¥59
课程目录
已完结/共 55 讲
第一章:Go语言简介 (4讲)
第二章:基本程序结构 (4讲)
第三章:常用集合 (3讲)
第四章:字符串 (1讲)
时长 16:47
第五章:函数 (2讲)
第六章:面向对象编程 (4讲)
第七章:编写好的错误处理 (2讲)
第八章:包和依赖管理 (2讲)
第九章:并发编程 (7讲)
第十章:典型并发任务 (5讲)
第十一章:测试 (3讲)
时长 11:48
时长 07:12
时长 06:15
第十二章:反射和Unsafe (3讲)
时长 08:18
时长 08:03
第十三章:常见架构模式的实现 (2讲)
第十四章:常见任务 (4讲)
时长 04:27
时长 05:14
第十五章:性能调优 (4讲)
第十六章:高可用性服务设计 (5讲)
Go 语言从入门到实战
登录|注册
留言
18
收藏
沉浸
阅读
分享
手机端
回顶部
当前播放: 33 | 对象池
00:00 / 00:00
高清
  • 高清
1.0x
  • 2.0x
  • 1.5x
  • 1.25x
  • 1.0x
  • 0.75x
  • 0.5x
网页全屏
全屏
00:00
付费课程,可试看
01 | Go语言课程介绍
02 | 内容综述
03 | Go语言简介:历史背景、发展现状及语言特性
04 | 编写第一个Go程序
05 | 变量、常量以及与其他语言的差异
06 | 数据类型
07 | 运算符
08 | 条件和循环
09 | 数组和切片
10 | Map声明、元素访问及遍历
11 | Map与工厂模式,在Go语言中实现Set
12 | 字符串
13 | Go语言的函数
14 | 可变参数和defer
15 | 行为的定义和实现
16 | Go语言的相关接口
17 | 扩展与复用
18 | 不一样的接口类型,一样的多态
19 | 编写好的错误处理
20 | panic和recover
21 | 构建可复用的模块(包)
22 | 依赖管理
23 | 协程机制
24 | 共享内存并发机制
25 | CSP并发机制
26 | 多路选择和超时
27 | channel的关闭和广播
28 | 任务的取消
29 | Context与任务取消
30 | 只运行一次
31 | 仅需任意任务完成
32 | 所有任务完成
33 | 对象池
34 | sync.pool对象缓存
35 | 单元测试
36 | Benchmark
37 | BDD
38 | 反射编程
39 | 万能程序
40 | 不安全编程
41 | 实现pipe-filter framework
42 | 实现micro-kernel framework
43 | 内置JSON解析
44 | easyjson
45 | HTTP服务
46 | 构建RESTful服务
47 | 性能分析工具
48 | 性能调优示例
49 | 别让性能被锁住
50 | GC友好的代码
51 | 高效字符串连接
52 | 面向错误的设计
53 | 面向恢复的设计
54 | Chaos Engineering
55 | 结课测试&结束语
登录 后留言

全部留言(18)

  • 最新
  • 精选
纛下靥狗
蔡老师您好 在对象池一课我参考之前的课程使用unsafe.Pointer在不放回的情况下打出了每个对象的地址,发现他们都是一样的, 这个时候结构体里没有定义任何成员。 我把NewObjPool的初始化对象改成了每个都赋予一个id int子成员的情况下10个对象打印出的地址就不同了(预期) 后来在网上查阅发现这个是空结构体,用unsafe.Sizeof发现占用的大小为0,所以每次初始化的位移就是0,所以每个对象的地址都是相同。 而如果增加一个int成员的话,Size就会变成8,然后地址的位移也是8. 另外老师github上的代码没有更新了最近。。。

作者回复: 很赞!在可执行的代码中学习! 代码我会尽快提交,并通知平台更新。

2019-04-04
12
Geek_d235ed
老师好,ch32 的对象池,我这边执行起来报了下面错误,能帮忙看下吗? # command-line-arguments [command-line-arguments.test] .\obj_pool_test.go:10:10: undefined: NewObjPool Compilation finished with exit code 2

作者回复: 我猜你是在命令行里制定了obj_pool_test.go, 所以obj_pool.go没有被编译。 直接在路径下使用go test -v执行看看

2020-12-31
2
Aprelude
package ch6 import ( "errors" "fmt" "testing" "time" "unsafe" ) type ReusableObj struct { } type ObjPool struct { bufChan chan *ReusableObj //用于缓冲可重用对象 } func NewObjPool(numOfObj int) *ObjPool { objPool := ObjPool{} objPool.bufChan = make(chan *ReusableObj, numOfObj) for i := 0; i < numOfObj; i++ { m := &ReusableObj{} fmt.Println("un:", unsafe.Pointer(m)) objPool.bufChan <- m } return &objPool } func (p *ObjPool) GetObj(timeout time.Duration) (*ReusableObj, error) { select { case ret := <-p.bufChan: return ret, nil case <-time.After(timeout): return nil, errors.New("time out") } } func (p *ObjPool) ReleaseObj(obj *ReusableObj) error { select { case p.bufChan <- obj: return nil default: return errors.New("overflow") } } func TestObjPool(t *testing.T) { pool := NewObjPool(10) for i := 0; i < 11; i++ { if v, err := pool.GetObj(time.Second * 1); err != nil { t.Error(err) } else { fmt.Println(unsafe.Pointer(v)) //if err := pool.ReleaseObj(v); err != nil { // t.Error(err) //} } } t.Log("done") } 忘记了 这个为什么每次输出的第地址都一样啊 大佬解释一下 不是new对象吗

作者回复: GO中为了优化如果结构体里没有字段只有方法,那么两个结构体的执行结果肯定相同,所以共用一个地址了。 所以你把结构体修改一下: type ReusableObj struct { x int } 再试试。

2020-07-15
2
2
田佳伟
老师,假如我用对象池当做MySQL连接池用的话,我创建100个连接,然后在并发情况下连接池空了,这个时候后续的query只能等待或者timeout吗?还有没有别的更好的方案

作者回复: 较常见的,还可以降级处理,超时后直接从缓存返回历史数据或返回默认数据。

2019-07-18
1
william
第一遍直接听,完全忘了,第二遍跟着敲一遍,受益匪浅,感谢老师(赞赞)

作者回复: 谢谢🙏编程一定要亲自动手调试

2021-08-12
金陵一只猪
老师,ReleaseObj 解释为 释放对象,但从代码上看,这个方法好像是 向对象池中放入一个对象,是不是我的理解有问题?

作者回复: 确切的说是把使用完的对象归还回去。

2021-02-25
老师你好,time out在项目中的正确处理是什么?应该不是只报个错,然后输出timeout吧。。

作者回复: 后面的高可用性课程会讲。继续看哦

2019-04-01
蓝士钦
一楼[ZY]的留言 “当一个channel满了之后 无法继续插入 会报错,但是放到协程里面却可以在满了之后 继续插入数据 为什么呢?” 我的理解是这样的: 1.你的代码里有生产者和消费者,使用for循环开启了10个协程,channel还没满的时候就被消费者提前消费掉了,其实只能添加10数据,可以把消费者去掉, 并且加上日志打印:代码如下: var wg sync.WaitGroup num := 10 ch := make(chan int, num) for i := 0; i < 1000; i++ { wg.Add(1) go func(i int) { ch <- i // 协程满后会阻塞,导致无法执行厦门的wg.Done()导致死锁报异常 fmt.Printf("执行协程:%d\n",i) wg.Done() }(i) wg.Wait() } 2.可以在一个协程里循环添加超过channel大小的数据,依旧会阻塞 func TestChannelPush(t *testing.T) { ch := make(chan int, 10) var wg sync.WaitGroup wg.Add(1) pushChannel(ch,&wg) wg.Wait() } func pushChannel(ch chan int, wg *sync.WaitGroup) { go func() { for i := 0; i < 100; i++ { ch <- i } wg.Done() }() } 因为这里用了WaitGroup,所以会有死锁,实际上是会阻塞。
2019-03-27
5
蓝士钦
补充一下ZY的留言,channel大小虽然只有10,for循环开启11个协程往channel添加数据,但是因为协程和主程序是异步的所以看不出阻塞,因为后面的消费者程序把channel的数据消费了,所以上面可能存在的阻塞又通了,一边生产一边消费,MQ经常堆包也是类似的情况,在主机内存空间有限的情况下如果消费者处理消息的速度比生产者慢,就有可能堆包,严重的就阻塞。
2019-03-27
4
「ZY」
蔡老师您好 这节课您里面讲到 当一个channel满了之后 无法继续插入 会报错 但是放到协程里面却可以在满了之后 继续插入数据 为什么呢? 申请的时候是10个 插入11个 num := 10 ch := make(chan int, num) for i := 0; i < num+1; i++ { go func(i int) { ch <- i }(i) } total := 0 for i := 0; i < num+1; i++ { total += <-ch } fmt.Println("for total-------", total)
2019-03-27
1
4
收起评论