고 루틴 중지 방법
메서드를 호출하고 채널에서 반환 된 값을 전달하는 고 루틴이 있습니다.
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()
}
일반적으로 고 루틴 a (별도의) 신호 채널을 전달합니다. 해당 신호 채널은 고 루틴을 중지하려는 경우 값을 입력하는 데 사용됩니다. 고 루틴은 해당 채널을 정기적으로 폴링합니다. 신호를 감지하는 즉시 종료됩니다.
quit := make(chan bool)
go func() {
for {
select {
case <- quit:
return
default:
// Do other stuff
}
}
}()
// Do stuff
// Quit goroutine
quit <- true
외부에서 고 루틴을 죽일 수는 없습니다. 고 루틴에 채널 사용을 중지하도록 신호를 보낼 수 있지만 고 루틴에 대한 처리는 어떤 종류의 메타 관리도 수행 할 수 없습니다. 고 루틴은 협력 적으로 문제를 해결하기위한 것이므로 오작동하는 것을 죽이는 것은 적절한 대응이 될 수 없습니다. 견고성을 위해 격리를 원한다면 아마도 프로세스가 필요할 것입니다.
일반적으로 채널을 생성하고 고 루틴에서 정지 신호를 수신 할 수 있습니다.
There two way to create channel in this example.
channel
context. In the example I will demo
context.WithCancel
The first demo, use 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")
}
The second demo, use 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")
}
I know this answer has already been accepted, but I thought I'd throw my 2cents in. I like to use the tomb package. It's basically a suped up quit channel, but it does nice things like pass back any errors as well. The routine under control still has the responsibility of checking for remote kill signals. Afaik it's not possible to get an "id" of a goroutine and kill it if it's misbehaving (ie: stuck in an infinite loop).
Here's a simple example which I tested:
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)
}
The output should look like:
# Loop the loop
# Loop the loop
# Loop the loop
# Loop the loop
# Death from above
Personally, I'd like to use range on a channel in a goroutine:
https://play.golang.org/p/qt48vvDu8cd
Dave has written a great post about this: http://dave.cheney.net/2013/04/30/curious-channels.
참고URL : https://stackoverflow.com/questions/6807590/how-to-stop-a-goroutine
'Programing' 카테고리의 다른 글
| LINQ의 LIKE 연산자 (0) | 2020.09.21 |
|---|---|
| jquery로 클릭 한 링크의 href를 얻는 방법은 무엇입니까? (0) | 2020.09.21 |
| Gradle에서 현재 OS를 감지하는 방법 (0) | 2020.09.21 |
| convert_tz는 null을 반환합니다. (0) | 2020.09.21 |
| 새 Mac OS X 터미널 창에서 명령 실행 (0) | 2020.09.21 |