go문장 및 그 집행 순서

3938 단어
goroutine는 병렬 프로그래밍 모드의 사용자급 라인을 대표합니다.
  운영체제 자체는 프로세스와 루틴이라는 두 가지 병행 실행 프로그램을 제공하는 도구를 제공한다.프로세스는 프로그램의 실행 과정을 설명하고 실행 중인 프로그램의 대표이다.루틴은 항상 프로세스 안에 있으며 프로세스에서 실행되는 제어 흐름으로 간주될 수 있습니다. (또는 코드가 실행되는 프로세스라고 할 수 있습니다.)
프로세스에 최소한 하나의 라인이 포함됩니다.만약 프로세스가 하나의 라인만 포함한다면, 그 안의 모든 코드는 직렬로 실행될 것이다.모든 프로세스의 첫 번째 루틴은 프로세스가 시작됨에 따라 만들어집니다. 이 루틴은 프로세스가 속한 프로세스의 메인 프로그램이라고 할 수 있습니다.
프로세스에 여러 개의 라인이 포함되어 있으면 코드가 병렬적으로 실행될 수 있습니다.프로세스의 첫 번째 라인을 제외하고 다른 라인은 프로세스에 이미 존재하는 라인에서 만들어진 것입니다.
  즉, 메인 라인 이외의 다른 라인은 코드로만 현저하게 만들고 삭제할 수 있다.이것은 우리가 프로그램을 작성할 때 수동으로 제어해야 한다. 운영체제와 프로세스 자체가 우리에게 이런 명령을 내리지 않고, 그것들은 우리의 명령을 충실하게 집행할 뿐이다.
단, Go 프로그램에서 Go 언어가 실행될 때 (runtime) 시스템은 그룹이 자동으로 시스템 레벨의 루틴을 만들고 삭제하도록 도와줍니다.이곳의 시스템 레벨 라인은 우리가 방금 말한 운영체제가 제공하는 라인을 가리킨다.
 에 대응하는 사용자급 루틴은 시스템급 루틴 위에 설치된 사용자(또는 우리가 작성한 프로그램)가 완전히 제어하는 코드 실행 절차를 가리킨다.사용자급 라인의 창설, 소각, 상태 변경, 그리고 그 중의 코드와 데이터는 모두 우리 프로그램 자체가 실현하고 처리해야 한다.
  이것은 많은 장점을 가져왔다. 예를 들어 그들의 창설과 소각은 운영체제를 통해 할 필요가 없기 때문에 속도가 매우 빠르다. 예를 들어 운영체제가 그들의 운행을 스케줄링하기를 기다리지 않기 때문에 왕왕 쉽게 제어할 수 있고 유연할 수 있다.
그러나 열세도 있다. 가장 뚜렷하고 가장 중요한 열세는 복잡하다.만약 우리가 시스템급 스레드만 사용한다면, 우리는 새로운 스레드가 실행되어야 하는 코드 세션을 가리키고, 스레드를 만들거나 없애는 명령을 내리면 된다. 기타 모든 구체적인 실현은 운영체제가 대신할 것이다.
  그러나 만약에 사용자급 라인을 사용한다면 우리는 명령 하달자이자 명령 집행자일 수밖에 없다.우리는 반드시 사용자급 라인과 관련된 모든 구체적인 조작을 전적으로 책임져야 한다.
  운영체제는 도움을 주지 않을 뿐만 아니라 우리의 구체적인 실현은 반드시 그것과 정확하게 연결되어야 한다. 그렇지 않으면 사용자급 라인이 병발되지 않고 심지어 정확하게 운행될 수 없다.
그러나 걱정하지 마세요. Go 언어는 독특한 병렬 프로그래밍 모델과 사용자급 루틴 goroutine이 있을 뿐만 아니라 goroutine, 시스템의 루틴을 조정하고 연결하는 데 사용되는 강력한 스케줄러도 가지고 있습니다.
이 스케줄러는 고 언어가 실행될 때 시스템의 중요한 구성 부분으로 주로 고 병렬 프로그래밍 모델 중의 세 가지 주요 요소를 총괄적으로 조정하는 것을 책임진다.즉, G(goroutine의 줄임말), P(processor의 줄임말), M(machine의 줄임말)이다.
 의 M은 시스템 레벨 스레드를 나타냅니다.P는 몇 개의 G를 적재할 수 있고 이 G들이 적시에 M과 연결되어 진정으로 운행될 수 있도록 하는 중개를 말한다.
  거시적으로 보면 G와 M은 P의 존재로 인해 다대다의 관계를 나타낼 수 있다.어떤 M과 연결되어 실행 중인 G가 어떤 이벤트(예를 들어 입출력이나 잠금 해제를 기다리는 것)로 인해 실행을 중단해야 할 때 스케줄러는 항상 제때에 발견하고 이 G를 저 M과 분리해서 계산 자원을 방출하여 실행을 기다리는 G의 사용을 제공한다.
스케줄러는 G가 실행을 재개해야 할 때 가능한 한 빨리 빈 계산 자원 (M 포함) 을 찾아 실행을 안배합니다.또한 M이 충분하지 않을 때 스케줄러는 운영체제에 새로운 시스템 라인을 신청하고, 어떤 M이 쓸모가 없을 때 스케줄러는 그것을 제때에 없애는 것을 책임진다.
스케줄러가 우리를 도와 많은 일을 했기 때문에 우리의 Go 프로그램은 항상 운영체제와 컴퓨터 자원을 효율적으로 이용할 수 있다.프로그램의 모든 goroutine도 충분히 스케줄링되고 그 중의 코드도 병발적으로 실행된다. 설령 이런 goroutine가 수만 개가 된다 하더라도 여전히 그럴 수 있다.
demo:
package main

import "fmt" 

func main() {
    for i:=0; i<10; i++ {
      go func() {
          fmt.Println(i)
      }()
    }
}

결과: 어떤 내용도 인쇄되지 않습니다.
원인: 하나의 프로세스에 하나의 주 라인이 있는 것과 유사하며, 각각의 독립된 Go 프로그램도 실행할 때 하나의 주 Goroutine가 있다.이 주 Goroutine는 Go 프로그램의 실행 준비 작업이 끝난 후에 자동으로 활성화되며, 우리가 수동으로 조작할 필요가 없습니다.
모든 고 언어는 일반적으로 하나의 함수를 가지고 호출된다. 이 호출된 함수는 흔히 고 함수라고 불리는데, 주 고로틴의 고 함수는 바로 프로그램 입구로서의main 함수이다.
반드시 주의해야 할 것은 고 함수가 진정으로 집행되는 시간은 소속된 고 문장이 집행되는 시간과 다르다는 것이다.프로그램이 go 문장을 실행할 때, Go 언어가 실행될 때, 시스템은 빈 G를 저장하는 G 대기열에서 G (즉 goroutine) 를 가져오려고 시도합니다. 빈 G를 찾을 수 없는 상황에서만 새로운 G를 만들 수 있습니다.
이것이 바로 왜 하나의 고로틴을 사용하고 하나의 고로틴을 만들지 않는다고 말하는 이유이다.이미 존재하는 Goroutine는 항상 유한하게 복용됩니다.
그리고 G를 만드는 비용도 매우 낮다.G를 만드는 것은 새 프로세스나 시스템 라인처럼 운영체제의 시스템 호출을 통해 이루어지지 않는다. Go 언어가 실행될 때 시스템 내부에서 완전히 할 수 있다. 더군다나 G는 코드 세션을 병렬적으로 실행해야 하는 상하문 환경일 뿐이다.
빈 G를 가져온 후 Go 언어가 실행될 때 시스템은 이 G로 현재의 Go 함수 (또는 이 함수에 있는 코드) 를 포장한 다음, 이 G를 실행 가능한 G를 저장하는 대기열에 추가합니다.
이런 대기열의 G는 항상 선입선출의 순서에 따라 실행할 때 시스템 내부의 스케줄러가 빨리 운행하도록 배정한다.비록 이것은 매우 빠를 것이지만, 위에서 말한 그 준비 작업들은 여전히 피할 수 없기 때문에, 시간 소모는 여전히 존재한다.
따라서 고 함수의 집행 시간은 그에 속하는 고 문장의 집행 시간보다 현저히 뒤떨어진다.
데모에서 주 goroutine의 코드가 실행되면 현재 Go 프로그램이 실행을 끝냅니다.아직 실행되지 않은 고루틴이 닫힙니다.
그러나 Go 프로그램은 이 Goroutine들이 어떤 순서로 실행될지 보장하지 않는다.주 고로틴은 우리가 수동으로 사용하는 다른 고로틴과 함께 스케줄링을 할 수 있고, 스케줄러가 고로틴의 코드가 일부분만 실행될 때 모든 고로틴이 더 공평하게 실행될 수 있도록 일시 정지할 수 있기 때문이다.
그래서 어느 고로틴이 먼저 집행하고 어느 고로틴이 나중에 집행되는지는 흔히 예측할 수 없는 것이다. 우리가 어떤 고언어가 제공하는 방식을 사용해서 인위적인 개입을 하지 않는 한.
따라서 데모의 결과: 대부분의 경우 잃어버리면 어떤 내용도 인쇄되지 않지만 일부분의 경우 내용이 인쇄되는 것을 배제하지 않는다. 예를 들어 10개의 9, 난서의 0-9

좋은 웹페이지 즐겨찾기