2013-11-22 3 views
2

두 가지 이상한 점이 있습니다. goroutine을 다룰 때 이상한 점

  1. 나는 조각 1000 개 번호를 만들었지 만 그것은 그냥 천 (246), 왜 246? 그리고 왜 인쇄?

  2. "log.Println ("hey ")"이 줄을 삭제하면 왜 그냥 0이 인쇄됩니까?

동기화 문제가있을 수 있지만 이전에 동의 프로그램을 작성하지 않았으므로 어떤 기사라도 좋습니다.

import (
     "log" 
     "runtime" 
) 

func main() { 

    count := 1000 
    slice := make([] int,count) 
    for i := 0; i <= count-1; i++ { 
    slice[i] =i 
    } 
    for _,v := range slice{ 
    go echo(v) 
    } 
    log.Println("hey")//if delete this line,it just print 0 
    runtime.Gosched() 
} 


func echo(v int) { 
    log.Println(v) 
} 

답변

3

메인 루틴이 완료되기 전에 실행 루틴이 실행되는 것은 아닙니다. 메인 루틴이 완료되면, 작성한 모든 이동 루틴이 완료 (또는 시작) 될 때까지 기다리지 않고 프로그램이 종료됩니다.

가장 쉬운 방법은 동기화 채널을 할당하고 각 에코 인스턴스에 전달하고 로그 문 뒤에 토큰을 쓰는 것입니다. 그런 다음 주 스레드는 복귀하기 전에 해당 채널에서 count 토큰을 읽어야합니다.

+0

하지만 난 마지막에 runtime.Gosched을()가 호출, 다른 사람이 백 우측 goroutines 때까지 주()을 기다려야한다? –

+2

@MaxLau, 아니, 그렇지 않습니다. 'runtime.Gosched()'는 스케줄러에게 다른 goroutine에 제어 흐름을 전달하도록 요청하지만, 다른 goroutine이'runtime.Gosched()'를 호출하거나 동등한 작업을 수행 할 때 제어 흐름이'main'으로 되돌아가는 것을 결코 막지 않습니다 스케줄링 측면에서의 행동. 실제로'Gosched()'호출은 다른 goroutine을 잠깐 동안 실행하게하고, 메인 goroutine은 다시 실행되어 그 직후에 종료됩니다. –

3

주 이동 루틴을 종료하면 이미 실행중인 이동 루틴을 기다리지 않습니다. 실행중인 이동 루틴을 동기화해야하며 내 경험상 sync.WaitGroup이 적합한 일반적인 솔루션입니다.

Playground

import (
    "log" 
    "sync" 
) 

func main() { 

    count := 1000 
    slice := make([]int, count) 
    for i := 0; i <= count-1; i++ { 
     slice[i] = i 
    } 
    wg := new(sync.WaitGroup) 
    for _, v := range slice { 
     wg.Add(1) 
     go echo(v, wg) 
    } 
    wg.Wait() 
} 

func echo(v int, wg *sync.WaitGroup) { 
    defer wg.Done() 
    log.Println(v) 
} 
+0

thx 멋쟁이,하지만 왜 내가 사용할 수 없어 runtime.Gosched() main() 끝에? "Gosched는 프로세서를 생산하여 다른 goroutine을 실행할 수 있습니다."라고 말합니다. –

+0

'runtime.Gosched()'만이 프로세서를 잠시 만듭니 다.'main()'이 다시 시작될 때 복귀 할 것이고 주된 go 루틴은 종료 될 것이고, 모든 background go 루틴을 죽인다. –

관련 문제