6

请问 go 怎么在主程简单对函数进行超时控制

 2 years ago
source link: https://www.v2ex.com/t/853649
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

V2EX  ›  Go 编程语言

请问 go 怎么在主程简单对函数进行超时控制

  Askiz · 9 小时 35 分钟前 via Android · 959 次点击
协程的超时控制可以用 select 简单实现,请问如果是在 for 循环里,每次循环执行一个函数,要求对这个函数进行超时控制(超时就直接退出函数),有什么优雅的实现方法?
17 条回复    2022-05-18 20:03:00 +08:00
ch2

ch2      9 小时 31 分钟前

select 已经算是优雅的了
Askiz

Askiz      9 小时 28 分钟前 via Android

@ch2 不好意思,我这边可能说得比较糊,就是主程序里有个函数 RunTask()在运行,怎么对这个函数进行超时控制呢,这个函数不是在协程中运行的
Herobs

Herobs      9 小时 27 分钟前 via iPhone

想要”控制”,必然要和 main 分开运行,那不就是要用协程嘛

或者函数主动实现超时退出,也是要用协程,不过逻辑在函数里面。
lysS

lysS      9 小时 15 分钟前

那么这个函数里面必须有 for 循环,每次循环的时候判断一下。其实就是这个函数要是可分的、不一定是循环。

比如
func a(){ time.Sleep(time.Hour) }
就不行,而
func b(){
time.Sleep(time.Minute)
time.Sleep(time.Minute)
time.Sleep(time.Minute)
}
就可以,超时时间精度是 1 分钟
sean4go01

sean4go01      8 小时 35 分钟前

@Askiz 我最近也遇到类似的问题了,不是协程。我是定时任务,执行一个任务执行比较花时间。应该是执行了一部分后,可能是超时退出了,但是不知道怎么控制这个超时时间。导致后面的任务没执行。
czyt

czyt      8 小时 30 分钟前

context
Juszoe

Juszoe      8 小时 0 分钟前

前段时间讨论过了 /t/851321
答案是没有办法从外部强制终止,只能让协程自己退出,比较好的方式是用 context 控制
lbp0200

lbp0200      7 小时 50 分钟前

context.WithTimeout
MarsCloud

MarsCloud      7 小时 46 分钟前   ❤️ 1

@Askiz 将 RunTask 转成一个 goroutine ,然后通过 select 以及 context 做控制。
MoYi123

MoYi123      7 小时 33 分钟前

没办法, 如果是进程 /线程可以通过定时器+kill/tgkill 实现, go 这种自己实现的协程就没有特别好的办法了.
Askiz

Askiz      6 小时 58 分钟前 via Android

@lbp0200 嗯嗯,看来也只能这样了
Askiz

Askiz      6 小时 54 分钟前 via Android

@Herobs 我想实现的是对 mysql 进行连接测试,发现这个标准库并没有超时控制,而 ssh 的连接测试是有自带一个 timeout 参数的。不过看了 net.DialTimeout 函数发现这个也是用多开一个 go 程+select 实现超时控制的。看来也只能用 go 程了。
EZVIK

EZVIK      6 小时 40 分钟前   ❤️ 1

用装饰器模式包装函数

```go
type RunTask func(int) float64

func RunTaskTimeout(fun RunTask, timeout time.Duration) RunTask {

return func(i int) float64 {

ch := make(chan float64)

go func() {
ch <- func(i int) float64 {
return func(i int) float64 {
return fun(i)
}(i)
}(i)
}()

select {
case f := <-ch:
return f
case <-time.After(timeout):
return -1
}
}
}

func main() {
runTask := RunTaskTimeout(Pi, time.Second)
data := []int{500, 5000, 50000, 500000, 5000000}
for i := 0; i < 10; i++ {
if res := runTask(data[i]); res < 0 {
break
} else {
fmt.Println(res)
}
}
fmt.Println("DONE.")
}

```
FrankAdler

FrankAdler      4 小时 33 分钟前

为什么要拒绝使用 goroutine 呢,配上 context 非常优雅了
Askiz

Askiz      2 小时 16 分钟前 via Android

学到了,感谢~
Askiz

Askiz      1 小时 36 分钟前

@EZVIK #13 感觉这么多闭包没必要呀,直接 ch <- fun(i) 不就可以了
Kisesy

Kisesy      53 分钟前

测试 mysql 连接? 用这个库 github.com/go-sql-driver/mysql ?
这个库不是可以带有 timeout 参数吗?

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK