runtime.Gosched는 정확히 무엇을합니까?
에서 투어 이동의 웹 사이트의 이동 1.5의 출시 이전 버전 , 코드 조각 거기에 그 같은 모습.
package main
import (
"fmt"
"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
runtime.Gosched()
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
출력은 다음과 같습니다.
hello
world
hello
world
hello
world
hello
world
hello
나를 괴롭히는 runtime.Gosched()것은 제거 될 때 프로그램이 더 이상 "world"를 인쇄하지 않는다는 것입니다.
hello
hello
hello
hello
hello
왜 이렇게이다? 어떻게 runtime.Gosched()실행에 영향을?
GOMAXPROCS 환경 변수를 지정하지 않고 Go 프로그램을 실행하면 Go 고 루틴이 단일 OS 스레드에서 실행되도록 예약됩니다. 그러나 프로그램을 멀티 스레드로 보이게하려면 (고 루틴의 용도가 그렇죠?) Go 스케줄러는 때때로 실행 컨텍스트를 전환해야하므로 각 고 루틴이 작업을 수행 할 수 있습니다.
앞서 말했듯이 GOMAXPROCS 변수가 지정되지 않은 경우 Go 런타임은 하나의 스레드 만 사용할 수 있으므로 goroutine이 계산이나 심지어 IO (일반 C 함수에 매핑되는 IO)와 같은 일반적인 작업을 수행하는 동안 실행 컨텍스트를 전환 할 수 없습니다. ). 컨텍스트는 Go 동시성 프리미티브가 사용되는 경우에만 전환 될 수 있습니다. 예를 들어 여러 채널을 켤 때 또는 스케줄러에게 컨텍스트를 전환하도록 명시 적으로 지시 할 때 (이것이 runtime.Gosched목적입니다.)
즉, 한 고 루틴의 실행 컨텍스트가 Gosched호출에 도달 하면 스케줄러는 실행을 다른 고 루틴으로 전환하도록 지시합니다. 귀하의 경우에는 두 개의 고 루틴이 있습니다. 메인 (프로그램의 '메인'스레드를 나타냄)과 추가로 go say. Gosched호출 을 제거 하면 실행 컨텍스트가 첫 번째 고 루틴에서 두 번째 고 루틴으로 전송되지 않으므로 '월드'가 없습니다. 때 Gosched존재, 스케줄러 전송하면 '안녕하세요'가 있고 '세계 인터리브 그래서 반대의 두 번째와 그에게 첫번째 goroutine에서 각 루프 반복에서 실행.
참고로이를 '협동 멀티 태스킹'이라고합니다. 고 루틴은 다른 고 루틴에 대한 제어권을 명시 적으로 양보해야합니다. 대부분의 최신 OS에서 사용되는 접근 방식은 '선점 형 멀티 태스킹'이라고합니다. 실행 스레드는 제어 전송과 관련이 없습니다. 스케줄러는 대신 실행 컨텍스트를 투명하게 전환합니다. 협력 적 접근 방식은 '그린 스레드', 즉 1 : 1을 OS 스레드에 매핑하지 않는 논리적 동시 코 루틴을 구현하는 데 자주 사용됩니다. 이것이 Go 런타임과 해당 고 루틴이 구현되는 방식입니다.
최신 정보
GOMAXPROCS 환경 변수에 대해 언급했지만 그것이 무엇인지 설명하지 않았습니다. 이 문제를 해결할 때입니다.
이 변수가 양수로 설정 N되면 Go 런타임은 N모든 녹색 스레드가 예약되는 최대 기본 스레드 를 생성 할 수 있습니다. 네이티브 스레드는 운영 체제 (Windows 스레드, pthreads 등)에 의해 생성되는 일종의 스레드입니다. 즉 N,이 1보다 크면 고 루틴이 다른 네이티브 스레드에서 실행되도록 예약되어 결과적으로 병렬로 실행될 수 있습니다 (최소한 컴퓨터 기능까지 : 시스템이 멀티 코어 프로세서를 기반으로하는 경우). 이러한 스레드가 실제로 병렬 일 가능성이 높습니다. 프로세서에 단일 코어가있는 경우 OS 스레드에 구현 된 선점 형 멀티 태스킹은 병렬 실행의 가시성을 생성합니다.)
runtime.GOMAXPROCS()환경 변수를 미리 설정하는 대신 함수를 사용하여 GOMAXPROCS 변수를 설정할 수 있습니다. 현재 대신 프로그램에서 다음과 같이 사용하십시오 main.
func main() {
runtime.GOMAXPROCS(2)
go say("world")
say("hello")
}
이 경우 흥미로운 결과를 관찰 할 수 있습니다. 'hello'및 'world'줄이 고르지 않게 삽입 될 수 있습니다. 예 :
hello
hello
world
hello
world
world
...
이는 고 루틴이 OS 스레드를 분리하도록 예약 된 경우 발생할 수 있습니다. 이것은 사실 선점 형 멀티 태스킹이 작동하는 방식 (또는 멀티 코어 시스템의 경우 병렬 처리)입니다. 스레드는 병렬이고 결합 된 출력은 결정적이지 않습니다. BTW, 당신은 Gosched전화를 나가거나 제거 할 수 있습니다 .GOMAXPROCS가 1보다 크면 효과가없는 것 같습니다.
다음은 runtime.GOMAXPROCS호출로 프로그램을 여러 번 실행했을 때 얻은 것입니다 .
hyperplex /tmp % go run test.go
hello
hello
hello
world
hello
world
hello
world
hyperplex /tmp % go run test.go
hello
world
hello
world
hello
world
hello
world
hello
world
hyperplex /tmp % go run test.go
hello
hello
hello
hello
hello
hyperplex /tmp % go run test.go
hello
world
hello
world
hello
world
hello
world
hello
world
See, sometimes output is pretty, sometimes not. Indeterminism in action :)
Another update
Looks like that in newer versions of Go compiler Go runtime forces goroutines to yield not only on concurrency primitives usage, but on OS system calls too. This means that execution context can be switched between goroutines also on IO functions calls. Consequently, in recent Go compilers it is possible to observe indeterministic behavior even when GOMAXPROCS is unset or set to 1.
Cooperative scheduling is the culprit. Without yielding, the other (say "world") goroutine may legally get zero chances to execute before/when main terminates, which per specs terminates all gorutines - ie. the whole process.
참고URL : https://stackoverflow.com/questions/13107958/what-exactly-does-runtime-gosched-do
'program story' 카테고리의 다른 글
| com.sun : tools : jar 아티팩트 누락 (0) | 2020.10.19 |
|---|---|
| 텍스트 파일에서 UTF-8이 아닌 문자를 제거하는 방법 (0) | 2020.10.19 |
| PHP에서 try… catch 블록을 효율적으로 사용하는 방법 (0) | 2020.10.19 |
| Neo4J는 ID로 노드 가져 오기 (0) | 2020.10.19 |
| 창 핸들이 만들어 질 때까지 컨트롤에서 Invoke 또는 BeginInvoke를 호출 할 수 없습니다. (0) | 2020.10.19 |