Go 正在等待具有超时的sync.Cond
是否有可能以某种简单的方式实现Java的等效功能Go 正在等待具有超时的sync.Cond,go,sync,Go,Sync,是否有可能以某种简单的方式实现Java的等效功能 wait(long timeMillis) 哪一个在监视器上等待(大致为互斥+秒)指定的时间量,如果没有发出信号则返回 我在文档中找不到任何东西,也无法在谷歌上搜索,虽然当然可以玩一些游戏,创建一个WaitGroup,并设置一个计时器goroutine pop,但仅仅获得这个简单的功能似乎很乏味/烦人/低效(顺便说一句,我遇到的任何底层系统线程库都直接支持它) 编辑:是的,我们也都读过了-再说一次,创建更多线程是一个“糟糕”(无性能)的解决方案
wait(long timeMillis)
哪一个在监视器上等待(大致为互斥+秒)指定的时间量,如果没有发出信号则返回
我在文档中找不到任何东西,也无法在谷歌上搜索,虽然当然可以玩一些游戏,创建一个WaitGroup,并设置一个计时器goroutine pop,但仅仅获得这个简单的功能似乎很乏味/烦人/低效(顺便说一句,我遇到的任何底层系统线程库都直接支持它)
编辑:是的,我们也都读过了-再说一次,创建更多线程是一个“糟糕”(无性能)的解决方案,通道也不太适合这个解决方案。想象一个典型的并发服务器Join()方法的用例。。。(请不要告诉我反转控件并使用侦听器模式。您并不总是有机会更改正在使用的API…不。没有简单的方法可以做到这一点,并且基于该线程,他们不会添加侦听器模式。(尽管与他们讨论可能会让您有所收获) 但总有一条艰难之路。2个选项:
Cond
。(请参阅)Cond
需要修补运行时中不需要修补的部分。(但是,正如我所说,这是可能的)
如果这是限制的话,很抱歉。go的大部分都非常简单-你可以经常跳到较低的一层,而不会有太多麻烦。但是调度程序不是这样的。它很神奇
这种魔力适用于大多数情况,他们在
sync
中添加了这些东西,以涵盖一些已知的情况,但事实并非如此。如果你觉得你找到了另一种,也许你可以说服他们添加它。(但这不仅仅是从另一种编程语言复制API,或者公开底层API的问题)我遇到了同样的问题,结果证明使用频道很容易解决
- 信号是通道上的发送信号
- 等待只是在通道上等待消息
- 带超时的等待只是对计时器和消息的选择
- 广播是一个循环发送消息,直到没有人听为止
主程序包
进口(
“同步”
“时间”
“fmt”
)
类型TMOCond结构{
我同步,储物柜
陈波
}
func NewTMOCond(l同步锁)*TMOCond{
返回和TMOCond{ch:make(chanbool),L:L}
}
func(t*TMOCond)Wait(){
t、 L.解锁()
您可以使用一个频道实现一个仅支持广播(无信号)的条件变量。以下是它的简要要点:
您也可以使用此技术在代码中替换频道并关闭旧频道。Gist中的代码使用不安全的指针和原子操作来允许在不获取主sync.Locker的情况下调用“Broadcast”。但是在您自己的代码中,您通常应该从获取锁中进行广播所以你不需要做任何不安全/原子的事情
虽然这种方法可行,但您可能还想签出:。如果您制作的加权信号量的限制为1,这也将为您提供所需的所有功能,这也是公平的。我在今年的GopherCon演讲中草拟了两个可能的备选方案(请参阅)。条件变量本节从幻灯片37开始,但备份幻灯片(101-105)将更详细地介绍此特定模式
正如zviadm所指出的,一个选项()是关闭一个通道
另一个选项()是让每个服务员分配一个1缓冲通道,并让广播员向缓冲区发送一个令牌进行广播
如果事件是持续状态,例如“队列为空”,则第三个选项()是使用1缓冲通道,并让每个接收器在持续状态下重新填充缓冲区。使等待超时成为可能。请参阅示例:
package main
import (
"fmt"
"sync"
"time"
"gitlab.com/jonas.jasas/condchan"
)
func main() {
cc := condchan.New(&sync.Mutex{})
timeoutChan := time.After(time.Second)
cc.L.Lock()
// Passing func that gets channel c that signals when
// Signal or Broadcast is called on CondChan
cc.Select(func(c <-chan struct{}) { // Waiting with select
select {
case <-c: // Never ending wait
case <-timeoutChan:
fmt.Println("Hooray! Just escaped from eternal wait.")
}
})
cc.L.Unlock()
}
主程序包
进口(
“fmt”
“同步”
“时间”
“gitlab.com/jonas.jasas/condchan”
)
func main(){
cc:=condchan.New(&sync.Mutex{})
timeoutChan:=时间后(时间秒)
cc.L.Lock()
//传递func,获取通道c,当
//在CondChan上调用信号或广播
cc.Select(func)(c)值得一读:你在使用appengine吗?特别是在Tim Cooper给出的链接上,请注意Ian Lance Taylor关于“条件变量通常不适合在Go中使用”的评论。不要试图用编写Java的方式编写Go。@TimCooper-很有趣,谢谢你的链接。但我看到的是“这是处理您的用例的错误方法”,并且…通道和“侧定时器”(goroutine/w timer)都不适用于该线程中的OP(或我)。他们只是关闭了他并关闭了他的票据。=/“这如何应用于我的示例?”“:你没有给出一个例子!你要求的是一个没有任何上下文的特定特性/函数,所以我认为这是可能的(基于这里糟糕的问题水平,其中包含“如何执行Caleb-与我在阻止tcp Accept()调用时使用的相同技巧
package main
import (
"fmt"
"sync"
"time"
"gitlab.com/jonas.jasas/condchan"
)
func main() {
cc := condchan.New(&sync.Mutex{})
timeoutChan := time.After(time.Second)
cc.L.Lock()
// Passing func that gets channel c that signals when
// Signal or Broadcast is called on CondChan
cc.Select(func(c <-chan struct{}) { // Waiting with select
select {
case <-c: // Never ending wait
case <-timeoutChan:
fmt.Println("Hooray! Just escaped from eternal wait.")
}
})
cc.L.Unlock()
}