메서드를 호출하고 채널에서 반환 된 값을 전달하는 고 루틴이 있습니다.
ch := make(chan int, 100)
go func(){
for {
ch <- do_stuff()
}
}()
그런 고 루틴을 어떻게 막을 수 있습니까?
메서드를 호출하고 채널에서 반환 된 값을 전달하는 고 루틴이 있습니다.
ch := make(chan int, 100)
go func(){
for {
ch <- do_stuff()
}
}()
그런 고 루틴을 어떻게 막을 수 있습니까?
답변:
편집 : 귀하의 질문이 goroutine 내부의 chan에 값을 보내는 것에 관한 것임을 깨닫기 전에이 답변을 서둘러 작성했습니다. 아래의 접근 방식은 위에서 제안한 추가 채널과 함께 사용하거나 이미 가지고있는 채널이 양방향이라는 사실을 사용하여 사용할 수 있습니다.
고 루틴이 채널에서 나오는 항목을 처리하기 위해서만 존재하는 경우 "close"내장 및 채널에 대한 특수 수신 양식을 사용할 수 있습니다.
즉, 짱에 항목을 보내고 나면 닫습니다. 그런 다음 고 루틴 내부에서 채널이 닫혔는지 여부를 보여주는 수신 연산자에 대한 추가 매개 변수를 얻습니다.
다음은 완전한 예입니다 (대기 그룹은 고 루틴이 완료 될 때까지 프로세스가 계속되는지 확인하는 데 사용됩니다).
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()
}
defer
to call을 사용하여보다 관용적으로 작성 되었으며 채널이 닫힐 때까지 모든 값을 반복 wg.Done()
하는 range ch
루프입니다.
일반적으로 고 루틴 a (별도의) 신호 채널을 전달합니다. 이 신호 채널은 고 루틴이 중지되기를 원할 때 값을 푸시하는 데 사용됩니다. 고 루틴은 해당 채널을 정기적으로 폴링합니다. 신호를 감지하는 즉시 종료됩니다.
quit := make(chan bool)
go func() {
for {
select {
case <- quit:
return
default:
// Do other stuff
}
}
}()
// Do stuff
// Quit goroutine
quit <- true
외부에서 고 루틴을 죽일 수는 없습니다. 고 루틴에 채널 사용을 중지하도록 신호를 보낼 수 있지만 고 루틴에 대한 핸들은 어떤 종류의 메타 관리도 수행 할 수 없습니다. 고 루틴은 협력 적으로 문제를 해결하기위한 것이므로 오작동하는 문제를 죽이는 것은 거의 적절한 대응이 아닙니다. 견고성을 위해 격리를 원한다면 아마도 프로세스가 필요할 것입니다.
일반적으로 채널을 생성하고 고 루틴에서 정지 신호를 수신 할 수 있습니다.
이 예에서 채널을 만드는 방법에는 두 가지가 있습니다.
채널
컨텍스트 . 이 예에서는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")
}
이 대답은 이미 받아 들여 졌다는 것을 알고 있지만 2 센트를 넣을 것이라고 생각했습니다. 저는 무덤 패키지 를 사용하는 것을 좋아 합니다. 기본적으로 지원 종료 채널이지만 오류를 다시 전달하는 것과 같은 좋은 기능을 수행합니다. 제어되는 루틴은 여전히 원격 킬 신호를 확인하는 책임이 있습니다. Afaik 고 루틴의 "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
tomb
예를 들어, 고 루틴 내부에서 어떤 일이 발생하여 패닉을 일으키는 경우를 대비하여 고 루틴이 무엇을하는지 테스트 해 보셨습니까 ? 내가 있으리라 믿고있어 그래서 기술적으로는 연기를 호출 여전히,이 경우, goroutine 종료를합니다 말하기 proc.Tomb.Done()
...
proc.Tomb.Done()
, 패닉이 프로그램을 충돌시키기 전에 실행될 것입니다. 메인 고 루틴이 일부 명령문을 실행할 수 있는 매우 작은 기회를 가질 수 있지만 다른 고 루틴의 패닉에서 복구 할 방법이 없으므로 프로그램이 여전히 충돌합니다. 문서에 따르면 "F가 패닉을 호출하면 F의 실행이 중지되고 F의 지연된 함수가 정상적으로 실행 된 다음 F가 호출자에게 반환됩니다. 프로세스는 현재 고 루틴의 모든 함수가 반환 될 때까지 스택을 계속합니다. 이 시점에서 프로그램이 충돌합니다. "
개인적으로 고 루틴의 채널에서 범위를 사용하고 싶습니다.
https://play.golang.org/p/qt48vvDu8cd
Dave는 이에 대한 훌륭한 게시물을 작성했습니다 : http://dave.cheney.net/2013/04/30/curious-channels .