今天这篇笔记我们记录sync包下面的Cond,Once和Pool
cond就是条件,当条件不满足的时候等待Wait(),条件满足后,继续执行。 通过Signal()和Broadcast()来通知wait结束,继续执行。我们先来看一个Signal通知的例子
func main() {
c := sync.NewCond(&sync.Mutex{})
queue := make([]interface{}, 0, 10)
removeFromQueue := func(delay time.Duration) {
time.Sleep(delay)
c.L.Lock()
queue = queue[1:]
fmt.Println("Removed from queue")
c.L.Unlock()
c.Signal()
}
for i := 0; i < 10; i++ {
c.L.Lock()
if len(queue) == 2 {
c.Wait()
}
fmt.Println("adding to the queue")
queue = append(queue, struct{}{})
go removeFromQueue(1 * time.Second)
c.L.Unlock()
}
fmt.Printf("queue length %d", len(queue))
}
这个程序是初始化了一个队列, 当队列的长度是2的时候,主goroutine等待, remove goruntine会删除队列中的数据,然后通过Signal方法通知主goroutine结束等待,继续执行添加。
这个程序执行的效果是这样的
adding to the queue
adding to the queue
Removed from queue
adding to the queue
Removed from queue
adding to the queue
Removed from queue
adding to the queue
Removed from queue
adding to the queue
Removed from queue
adding to the queue
Removed from queue
adding to the queue
Removed from queue
adding to the queue
Removed from queue
adding to the queue
可以看到当添加了两个后,就等待了,后面remove一个就添加一个,最后还有两个还没有来得及remove,主goroutine就退出了。
如果把c.Signal去掉,那么就会报死锁的错误, 因为主的goroutine等待了,子的gorountine也执行完了,就是都asleep了,就导致了报错。
adding to the queue
adding to the queue
Removed from queue
Removed from queue
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [sync.Cond.Wait]:
sync.runtime_notifyListWait(0xc000064050, 0x0)
C:/Program Files/Go/src/runtime/sema.go:517 +0x152
sync.(*Cond).Wait(0xeded38?)
C:/Program Files/Go/src/sync/cond.go:70 +0x8c
main.main()
C:/Learn/go/helloworld/goroutinelearn/class4/main.go:30 +0x331
exit status 2
如果仅仅是通知一个等待一个,通过channel就可以做到。 如果要通知多个goroutine,那么就需要用到Broadcast. 我们把上面的例子稍微改动一下,让多个删除的goroutine等待插入goroutine的通知,代码如下所示
c := sync.NewCond(&sync.Mutex{})
queue := make([]interface{}, 0, 10)
var waitgroup sync.WaitGroup
removeFromQueue := func(delay time.Duration) {
c.L.Lock()
for len(queue) < 1 {
c.Wait()
}
queue = queue[1:]
fmt.Println("Removed from queue")
waitgroup.Done()
c.L.Unlock()
}
for i := 0; i < 2; i++ {
c.L.Lock()
go removeFromQueue(1 * time.Second)
go removeFromQueue(1 * time.Second)
c.L.Unlock()
}
waitgroup.Add(4)
for i := 0; i < 4; i++ {
c.L.Lock()
fmt.Println("adding to the queue")
queue = append(queue, struct{}{})
c.Broadcast()
c.L.Unlock()
}
waitgroup.Wait()
我们故意做成一次循环调用两个删除goroutine, 然后在删除里面当queue的数量为空的时候等待,
插入的时候,通过Broadcast来广播这个消息。程序运行结果
adding to the queue
adding to the queue
adding to the queue
Removed from queue
Removed from queue
Removed from queue
adding to the queue
Removed from queue
结果可以看出,添加了之后,随后就能删除掉。 通知多个等待的goroutine,Broadcast还是比较有用。
once 我们顾名思意就是一次, 只运行一次的意思。 这种对于只需要执行一次的功能会非常有用。
看下面的示例代码
var count int
var lock sync.RWMutex
increment := func() {
lock.Lock()
count++
lock.Unlock()
}
decrement := func() {
lock.Lock()
fmt.Printf(" call decrement \n")
count--
lock.Unlock()
}
var once sync.Once
var increments sync.WaitGroup
increments.Add(100)
for i := 0; i < 100; i++ {
go func() {
defer increments.Done()
//increment()
once.Do(increment)
}()
}
once.Do(decrement)
increments.Wait()
fmt.Printf("Count is %d \n", count)
代码的输出为“Count is 1”, 我们通过once.Do 调用了increment 100次, 调用了 decrement 1次,但是实际上increment只被调用了一次。 once.Do 是保证它只被调用一次,不是细到方法,不是说一个方法调用一次,而是所有的都只调用一次。
谈到池,我们想到最多的就是线程池或者数据库连接池, 也比较好理解,就是创建一个资源比较耗时的时候,我们通过池来缓存一些资源,这样就不用每次都创建。
看下面示例代码
connPool := warmServiceConnCache()
connPool.Put(connPool.New())
connPool.Put(connPool.New())
for i := 1; i < 10; i++ {
conn1 := connPool.Get().(*Conncetor)
conn1.connect()
connPool.Put(conn1)
}
}
func warmServiceConnCache() *sync.Pool {
p := &sync.Pool{
New: connectToService,
}
return p
}
type Conncetor struct {
}
func (connector *Conncetor) connect() {
fmt.Println(" connecting")
}
func connectToService() interface{} {
fmt.Println(" creating new instance")
return new(Conncetor)
}
我们通过warmServiceConnCache 来返回一个Pool, 然后往这个Pool 中放入两个Connector,
通过Pool.Get()方法拿到创建的Connector, 调用了10次, 都是从Pool里面拿对象,而不需要创建10次,节省了资源。
程序的输出结果如下
creating new instance
creating new instance
connecting
connecting
connecting
connecting
connecting
connecting
connecting
connecting
connecting
这三个类,对于写并发程序还是很有作用,光看不是很理解怎么使用,通过敲代码,修改代码,能够对他们的用法有比较清晰的理解。
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
在我的路线文件中我有:match'graphs/(:id(/:action))'=>'graphs#(:action)'如果是GET请求(工作)或POST请求(不工作),我想匹配它我知道我可以使用以下方法在资源中声明POST请求:post'/'=>:show,:on=>:member但是我怎样才能为比赛做到这一点呢?谢谢。 最佳答案 如果你同时想要POST和GETmatch'graphs/(:id(/:action))'=>'graphs#(:action)',:via=>[:get,:post]编辑默认值可以设置如下match'g
关闭。这个问题是off-topic.它目前不接受答案。想改进这个问题吗?Updatethequestion所以它是on-topic用于堆栈溢出。关闭11年前。Improvethisquestion我不经常使用ruby-通常它加起来相当于每两个月或更长时间编写一次脚本。我的大部分编程都是使用C++进行的,这与ruby有很大不同。由于我与ruby之间的差距如此之大,我总是忘记语言的基本方面(比如解析文本文件和其他简单的东西)。我想每天练习一些基本的东西,我想知道是否有一些我可以订阅的网站,并且会向我发送当天的Ruby问题或类似的东西。有人知道这样的站点/Internet服务吗?
如果特定语言环境中缺少翻译,如何配置i18n以使用en语言环境翻译?当前已插入翻译缺失消息。我正在使用RoR3.1。 最佳答案 找到相似的question这里是答案:#application.rb#railswillfallbacktoconfig.i18n.default_localetranslationconfig.i18n.fallbacks=true#railswillfallbacktoen,nomatterwhatissetasconfig.i18n.default_localeconfig.i18n.fallback
在我的双语Rails4应用程序中,我有一个像这样的LocalesController:classLocalesController用户可以通过此表单更改其语言环境:deflocale_switcherform_tagurl_for(:controller=>'locales',:action=>'change_locale'),:method=>'get',:id=>'locale_switcher'doselect_tag'set_locale',options_for_select(LANGUAGES,I18n.locale.to_s)end这有效。但是,目前用户无法通过URL更改
我使用Ruby编程已经有一段时间了,现在只使用Ruby的标准MRI实现,但我一直对我经常听到的其他实现感到好奇。前几天我在读有关Rubinius的文章,这是一个用Ruby编写的Ruby解释器。我试着在不同的地方查找它,但我很难弄清楚这样的东西到底是如何工作的。我在编译器或语言编写方面从来没有太多经验,但我真的很想弄明白。一门语言究竟如何才能被自己解释?编译中是否有一个我不明白这有意义的基本步骤?有人可以像我是个白痴一样向我解释这个吗(因为无论如何这都不会太离谱) 最佳答案 它比你想象的要简单。Rubinius并非100%用Ruby编