停止在goroutine中的所有递归函数。

huangapple go评论114阅读模式
英文:

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 &lt;-quit:
			return 0
		default:
		}
	}

	total := 0

	for i := 0; i &lt; x; i++ {

		y := RecursiveFunc(x, depth - 1, quit)

		if y &gt; 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 (
	&quot;fmt&quot;
	&quot;time&quot;
	&quot;sync&quot;
)

func main() {

	quit := make(chan bool)
	wg := &amp;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 &lt;- true` doesn&#39;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 &lt;- true. However, quit &lt;- 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.ContextDone()通道关闭,并且被调用的函数将在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 &lt;-ctx.Done():
		return 0
	default:
	}

	total := 0

	for i := 0; i &lt; x; i++ {

		y := RecursiveFunc(ctx, x, depth-1)

		if y &gt; 0 {
			total += y
		}

	}

	return total
}

And here is how you can call the function with the new signature:

func main() {

	wg := &amp;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 &lt;-quit:
        quit &lt;- 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 := &lt;-xChan:
		log.Println(&quot;get chan result :&quot;, result)
		break
	}
}

func recursion(i int, xChan chan int) {
	if i &gt;= 10 {
		xChan &lt;- i
		close(xChan)
		return
	}
	a := i + i
	log.Println(&quot;a :&quot;, 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

huangapple
  • 本文由 发表于 2017年3月5日 16:14:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/42606049.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定