我有一个调用方法的goroutine,并在频道上传递返回的值:

ch := make(chan int, 100)
go func(){
    for {
        ch <- do_stuff()
    }
}()

如何停止这样的gor绕?

有帮助吗?

解决方案

编辑: 在意识到您的问题是要向Goroutine内部的木发送值之前,我匆忙地写了这个答案。下面的方法可以按照上面建议的额外的木材使用,也可以使用已经是双向的木材的事实,您可以仅使用一个...

如果您的goroutine仅仅是为了处理木出来的物品,则可以使用“近距离”的内置和频道的特殊接收表格。

也就是说,一旦您在陈门上发送项目后,就可以将其关闭。然后在goroutine内部,您将获得一个额外的参数,以显示该频道是否已关闭。

这是一个完整的示例(使用WaitGroup来确保该过程一直持续到Goroutine完成为止):

package main

import "sync"
func main() {
    var wg sync.WaitGroup
    wg.Add(1)

    ch := make(chan int)
    go func() {
        for {
            foo, ok := <- ch
            if !ok {
                println("done")
                wg.Done()
                return
            }
            println(foo)
        }
    }()
    ch <- 1
    ch <- 2
    ch <- 3
    close(ch)

    wg.Wait()
}

其他提示

通常,您通过Goroutine A(可能是单独的)信号通道。当您希望Goroutine停止时,该信号通道用于将值推入。 goroutine进行了定期进行的调查。一旦检测到信号,它就会退出。

quit := make(chan bool)
go func() {
    for {
        select {
        case <- quit:
            return
        default:
            // Do other stuff
        }
    }
}()

// Do stuff

// Quit goroutine
quit <- true

你不能从外面杀死戈洛蒂。您可以向Goroutine发出信号,以停止使用通道,但是Goroutines没有任何手柄可以进行任何类型的元管理。 Goroutines旨在合作解决问题,因此杀死一个不当行为的问题几乎永远不会是足够的反应。如果您想隔离鲁棒性,则可能需要一个过程。

通常,您可以创建一个通道并在Goroutine中接收停止信号。

在此示例中有两种创建频道的方法。

  1. 渠道

  2. 语境. 。在示例中,我将演示 context.WithCancel

第一个演示,使用 channel:

package main

import "fmt"
import "time"

func do_stuff() int {
    return 1
}

func main() {

    ch := make(chan int, 100)
    done := make(chan struct{})
    go func() {
        for {
            select {
            case ch <- do_stuff():
            case <-done:
                close(ch)
                return
            }
            time.Sleep(100 * time.Millisecond)
        }
    }()

    go func() {
        time.Sleep(3 * time.Second)
        done <- struct{}{}
    }()

    for i := range ch {
        fmt.Println("receive value: ", i)
    }

    fmt.Println("finish")
}

第二个演示,使用 context:

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    forever := make(chan struct{})
    ctx, cancel := context.WithCancel(context.Background())

    go func(ctx context.Context) {
        for {
            select {
            case <-ctx.Done():  // if cancel() execute
                forever <- struct{}{}
                return
            default:
                fmt.Println("for loop")
            }

            time.Sleep(500 * time.Millisecond)
        }
    }(ctx)

    go func() {
        time.Sleep(3 * time.Second)
        cancel()
    }()

    <-forever
    fmt.Println("finish")
}

我知道这个答案已经被接受,但是我想我会把我的两分化扔进去。我喜欢使用 包裹。基本上,这是一个戒烟频道,但它做得很好,例如传递任何错误。受到控制的例程仍然有责任检查远程杀戮信号。 Afaik不可能获得Goroutine的“ ID”,如果它表现不佳(即:卡在无限的循环中)。

这是我测试的一个简单示例:

package main

import (
  "launchpad.net/tomb"
  "time"
  "fmt"
)

type Proc struct {
  Tomb tomb.Tomb
}

func (proc *Proc) Exec() {
  defer proc.Tomb.Done() // Must call only once
  for {
    select {
    case <-proc.Tomb.Dying():
      return
    default:
      time.Sleep(300 * time.Millisecond)
      fmt.Println("Loop the loop")
    }
  }
}

func main() {
  proc := &Proc{}
  go proc.Exec()
  time.Sleep(1 * time.Second)
  proc.Tomb.Kill(fmt.Errorf("Death from above"))
  err := proc.Tomb.Wait() // Will return the error that killed the proc
  fmt.Println(err)
}

输出应该看起来像:

# Loop the loop
# Loop the loop
# Loop the loop
# Loop the loop
# Death from above

就个人而言,我想在Goroutine中使用频道上的范围:

https://play.golang.org/p/qt48vvdu8cd

戴夫(Dave)写了一篇很棒的文章: http://dave.cheney.net/2013/04/30/curious-channels.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top