我写了一个代码剪切,创建一个长度为0的计时器,它不会立即过期(这是我的预期)。一个非常短的睡眠呼叫确实使它过期,但我很困惑为什么。
我关心的原因是使用这个想法的代码有一个片段,在低概率错误时返回0,并且认为应该将计时器设置为立即过期,并重试一个函数。我不相信这里所需的纳秒睡眠会影响我的实施,但它让我感到困扰。
我犯了错误,这是预期的行为吗?
谢谢!
package main
import (
"fmt"
"time"
)
func main() {
testTimer := time.NewTimer(time.Duration(0) * time.Millisecond)
fmt.Println(Expired(testTimer))
time.Sleep(time.Nanosecond)
fmt.Println(Expired(testTimer))
}
func Expired(T *time.Timer) bool {
select {
case <-T.C:
return true
default:
return false
}
}
游乐场链接:https://play.golang.org/p/xLLHoR8aKq
打印
false
true
答案 0 :(得分:5)
time.NewTimer()
不保证最长等待时间。它只保证最小等待时间。引用其文档:
NewTimer会创建一个新的计时器,该计时器将在至少持续时间d 之后在其频道上发送当前时间。
所以将零持续时间传递给time.NewTimer()
,返回的time.Timer
不会立即“过期”并不奇怪。
如果实现将检查传递的持续时间是否为零,则返回的计时器可以立即“过期”,并且在返回之前会在计时器的通道上发送一个值,但事实并非如此。相反,它正常地启动一个内部计时器,就像它在任何给定的持续时间一样,它将负责在其通道上发送一个值,但仅在将来的某个时间。
请注意,对于多个CPU内核且runtime.GOMAXPROCS()
大于1的情况,另一个goroutine(time
包内部)在{{1}之前在定时器通道上发送值的可能性很小。返回,但这是一个非常小的机会......此外,由于这是实现细节,未来版本可能会添加此“优化”以检查0传递的持续时间,并按预期执行,但与所有实现细节一样,不要指望它。依靠记录的内容,不再期待。
答案 1 :(得分:1)
Go的计时器功能保证至少指定指定的时间。分别参阅Sleep和NewTimer的文档:
睡眠暂停当前goroutine至至少持续时间d。负或零持续时间会导致Sleep立即返回。
NewTimer会创建一个新的计时器,该计时器将在至少持续时间d之后在其频道上发送当前时间。
(强调补充)
在你的情况下,你根本不应该在你根本不想睡觉的情况下使用计时器。
答案 2 :(得分:0)
这是由于设置计时器对象所需的内部时间。如果您在下面的游乐场链接中注意到计时器在适当的时间到期,但是设置它并启动它的内部例行程序需要比Sleep
函数更长的时间来检查它。
当计时器到期时,当前时间将在C(通道)上发送
因此,您会注意到它过期后仍会发送原始时间,因为它已经在纳秒package main
import (
"fmt"
"time"
)
func main() {
testTimer := time.NewTimer(0 * time.Millisecond)
Expired(testTimer)
time.Sleep(time.Nanosecond)
Expired(testTimer)
n := time.Now()
fmt.Printf("after waiting: %d\n", n.UnixNano())
}
func Expired(T *time.Timer) bool {
select {
case t:= <-T.C:
fmt.Printf("expired %d\n", t.UnixNano())
return true
default:
n := time.Now()
fmt.Printf("not expired: %d\n", n.UnixNano())
return false
}
}
完成之前就已过期。
https://play.golang.org/p/Ghwq9kJq3J
function urlIsPublic($ip_list) {
$ips = explode(',', $ip_list);
foreach($ips as $ip) {
$ip = trim($ip);
if(filter_var($ip,
FILTER_VALIDATE_IP,
FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)
!== false) {
return $ip;
}
}
return false;
}