英文:
Stop all recursive functions in a goroutine
问题
启动一个运行递归函数的goroutine,我想发送一个信号来停止这些递归函数。这是函数(功能不重要):
func RecursiveFunc(x int, depth int, quit chan bool) int {
if depth == 0 {
return 1
}
if quit != nil {
select {
case <-quit:
return 0
default:
}
}
total := 0
for i := 0; i < x; i++ {
y := RecursiveFunc(x, depth - 1, quit)
if y > 0 {
total += y
}
}
return total
}
这个函数可能需要很长时间才能完成,我想在发送退出信号后停止它,并使用结果(无论是什么)。运行它的代码如下:
import (
"fmt"
"time"
"sync"
)
func main() {
quit := make(chan bool)
wg := &sync.WaitGroup{}
result := -1
go func() {
defer wg.Done()
wg.Add(1)
result = RecursiveFunc(5, 20, quit)
}()
time.Sleep(10 * time.Millisecond)
close(quit) // 使用 `quit <- true` 不起作用
wg.Wait()
fmt.Println(result)
}
为了停止goroutine,我使用了一个名为quit
的通道,关闭它后程序可以正常工作,但是我不想真正关闭通道,我只想发送一个信号quit <- true
。然而,quit <- true
不起作用,可能只会停止一个递归实例。
如何通过发送退出信号来停止所有递归函数的实例?
英文:
Staring a goroutine which runs a recursive function, I want to send a signal to stop those recursive functions. This is the function (the functionality is not important):
func RecursiveFunc(x int, depth int, quit chan bool) int {
if depth == 0 {
return 1
}
if quit != nil {
select {
case <-quit:
return 0
default:
}
}
total := 0
for i := 0; i < x; i++ {
y := RecursiveFunc(x, depth - 1, quit)
if y > 0 {
total += y
}
}
return total
}
This function may take a long time to be done and I want stop it after sending a quit signal and use the result (whatever it is). To run it:
import (
"fmt"
"time"
"sync"
)
func main() {
quit := make(chan bool)
wg := &sync.WaitGroup{}
result := -1
go func() {
defer wg.Done()
wg.Add(1)
result = RecursiveFunc(5, 20, quit)
}()
time.Sleep(10 * time.Millisecond)
close(quit) // Using `quit <- true` doesn't work
wg.Wait()
fmt.Println(result)
}
To stop the goroutine, I'm using a channel say quit
and after closing it, the program works well, however I don't want really close the channel and I want just send a signal quit <- true
. However, quit <- true
doesn't work and I probably quits only one instance of recursion.
How can I stop all instances of recursive function by sending a quit signal?
答案1
得分: 6
你可以使用context来完成你要做的事情。
你可以将一个context.Context
对象作为函数的第一个参数传递进去,这样你就可以从外部停止该函数,并调用相应的cancel
函数向该函数发送一个“取消信号”。这将导致context.Context
的Done()
通道关闭,并且被调用的函数将在select
语句中收到取消信号的通知。
以下是函数如何使用context.Context
处理取消信号的示例代码:
func RecursiveFunc(ctx context.Context, x int, depth int) int {
if depth == 0 {
return 1
}
select {
case <-ctx.Done():
return 0
default:
}
total := 0
for i := 0; i < x; i++ {
y := RecursiveFunc(ctx, x, depth-1)
if y > 0 {
total += y
}
}
return total
}
以下是如何使用新签名调用该函数的示例代码:
func main() {
wg := &sync.WaitGroup{}
result := -1
ctx, cancel := context.WithCancel(context.Background())
go func() {
defer wg.Done()
wg.Add(1)
result = RecursiveFunc(ctx, 5, 20)
}()
time.Sleep(10 * time.Millisecond)
cancel()
wg.Wait()
fmt.Println(result)
}
英文:
You can do the what you are going to do using context.
You can pass a context.Context
object as the first parameter to the function which you need to stop from outside, and call the corresponding cancel
function to send a "cancellation signal" to the function, which will cause the Done()
channel of the context.Context
to be closed, and the called function will thus be notified of the cancellation signal in a select
statement.
Here is how the function handles the cancellation signal using context.Context
:
func RecursiveFunc(ctx context.Context, x int, depth int) int {
if depth == 0 {
return 1
}
select {
case <-ctx.Done():
return 0
default:
}
total := 0
for i := 0; i < x; i++ {
y := RecursiveFunc(ctx, x, depth-1)
if y > 0 {
total += y
}
}
return total
}
And here is how you can call the function with the new signature:
func main() {
wg := &sync.WaitGroup{}
result := -1
ctx, cancel := context.WithCancel(context.Background())
go func() {
defer wg.Done()
wg.Add(1)
result = RecursiveFunc(ctx, 5, 20)
}()
time.Sleep(10 * time.Millisecond)
cancel()
wg.Wait()
fmt.Println(result)
}
答案2
得分: 1
我最近也遇到了类似的情况,就像你的情况一样,退出信号被递归分支中的一个消耗掉,导致其他分支没有信号。我通过在函数返回之前将停止信号转发到通道来解决这个问题。
例如,你可以修改递归函数中的 select 语句如下:
if quit != nil {
select {
case <-quit:
quit <- true // 转发信号
return 0
default:
}
}
英文:
I was in a similar situation recently and like your case, the quit signal was consumed by one of the recursion branch leaving the other branches without a signal. I solved this by forwarding the stop signal to the channel before returning from the function.
For example, you can modify the select inside the recursive function to be:
if quit != nil {
select {
case <-quit:
quit <- true // forward the signal
return 0
default:
}
}
答案3
得分: 0
// 递归函数无限循环直到条件 >= 10 成立,不要忘记关闭通道并返回
func main() {
x := 1
xChan := make(chan int)
go recursion(x, xChan)
select {
case result := <-xChan:
log.Println("获取通道结果:", result)
break
}
}
func recursion(i int, xChan chan int) {
if i >= 10 {
xChan <- i
close(xChan)
return
}
a := i + i
log.Println("a:", a)
recursion(a, xChan)
}
英文:
function recursion loop infinitely util the condition >= 10 matchs, don't forget to close channel and return
func main() {
x := 1
xChan := make(chan int)
go recursion(x, xChan)
select {
case result := <-xChan:
log.Println("get chan result :", result)
break
}
}
func recursion(i int, xChan chan int) {
if i >= 10 {
xChan <- i
close(xChan)
return
}
a := i + i
log.Println("a :", a)
recursion(a, xChan)
}
答案4
得分: -1
尝试添加标志以继续执行,但可能不是线程安全的。
var finishIt bool
func RecursiveFunc(x int, depth int, quit chan bool) int {
if finishIt {
return 0
}
//其他代码在这里
}
//一些代码在这里,但然后我们决定停止它
finishIt = true
英文:
Try to add flag to continue execution, but it can be not thread safe.
var finishIt bool
func RecursiveFunc(x int, depth int, quit chan bool) int {
if finishIt {
return 0
}
//other code here
}
//some code here, but than we decide to stop it
finishIt = true
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论