>  기사  >  백엔드 개발  >  Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

咔咔
咔咔원래의
2021-07-07 16:13:502031검색

Go의 고루틴과 채널에 대해 이야기해보겠습니다

  • 머리말
  • 1.goroutine
    • Definition
    • 고루틴 사용법을 알아보려면 먼저 사례를 살펴보세요
    • 채널이란
  • 2.
    • 기본 사용법
    • 채널이 매개변수로 전달됩니다
    • 여러 채널 만들기
    • 채널을 반환 값으로 사용
    • 버퍼 채널
    • 채널이 닫힙니다

    권장 관련 기사: "Go의 동시 프로그래밍에 대해 이야기합니다( 2)"

    머리말

예전에 바둑 언어를 배울 때 그루틴과 채널을 보고 건너뛰었습니다.

당시에는 전혀 심각하게 생각하지 않았는데 왜 그렇게 복잡하다고 생각하시나요? (당시 제 심정)

최근에 Go에서 동시 프로그래밍을 보다가 내용이 다 이 부분이라 쯧쯧 쯧쯧했는데, 보시면 아시겠지만 살펴보니 그리 어렵지는 않습니다.

때로는 보고 싶지 않은 것을 치워두고 집중해서 확인해보면 뜻밖의 이득을 얻을 수도 있습니다.

오늘 글은 간단한 설명입니다. 카카도 바둑 강좌를 신청했는데 어떤 강좌를 통해 좀 더 이해가 되는지 알아보고 심도 있는 보충을 하도록 하겠습니다.

1. goroutine

Definition

  • 함수 앞에 go만 추가하면 됩니다
  • 정의에서 비동기 함수인지 구분할 필요는 없습니다
  • 스케줄러가 할 것입니다 전환할 수 있는 지점은 많습니다. 이는 단지 참고 사항일 뿐이며, 전환이 보장되거나 다른 곳에서는 전환되지 않을 것이라는 보장은 없습니다. IO 작업, 채널, 잠금 대기, 함수 호출, Runtime.Gosched() 등 . .
  • race를 사용하여 데이터 액세스 충돌 감지

먼저 goroutine 사용 방법을 알아보려면 사례를 읽어보세요

먼저 사례를 살펴보겠습니다

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

이 사례는 go in go라는 키워드만 사용하는 간단한 동시 실행 코드입니다.

이 코드가 무엇을 출력할지 살펴보겠습니다

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

위 그림에서 이 코드 줄은 아무것도 출력하지 않고 직접 종료되는 것을 볼 수 있습니다.

직접 종료하는 이유는 코드의 메인 인쇄와 fmt 인쇄가 동시에 실행되기 때문입니다. fmt가 데이터가 오기 전에 긴급하게 인쇄하면 외부 루프가 이미 종료된 후 바로 종료됩니다.

Go 언어로! 주요 기능이 종료된 후 모든 고루틴을 직접 종료한다고 가정하므로 고루틴이 오기 전에 긴급 인쇄 데이터가 반환되는 현상이 발생합니다.

그럼 인쇄된 데이터를 어떻게 볼 수 있는지 궁금하시죠? 사실 아주 간단합니다. 메인 함수가 실행된 후 급하게 종료하지 말고 잠시 기다리시면 됩니다. 케이스를 보세요

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

이번에는 원하는 결과가 표시됩니다.

이 경우 열린 고루틴 개수가 10개인데 1000개로 바꾸면 어떻게 될까요?

1,000명이 동시에 인쇄하는 것처럼 결과는 여전히 정상적으로 표시됩니다.

그럼 10을 설정하는 것이 1000과 무슨 관련이 있나요?

운영체제에 익숙한 분들은 스레드 10개 열어도 문제 없고, 스레드 100개 열어도 큰 문제는 없다는 걸 아실텐데 거의 충분합니다.

일반적으로 시스템에서는 수십 개의 스레드를 열면 충분하지만, 1,000명이 동시에 한 가지 작업을 수행해야 한다면 스레드를 사용하여 문제를 해결할 수 없으며 비동기식 방법이 필요합니다.

하지만 Go 언어에서는! go 키워드를 직접 사용하면 동시에 실행할 수 있습니다.

다음으로 go가 동시에 1000명을 인쇄할 수 있는 이유에 대해 이야기해 보겠습니다.

이란 무엇입니까? 먼저 코루틴과 스레드의 차이점을 살펴보겠습니다.

코루틴은 경량 스레드, 비선점형 멀티태스킹, 코루틴이 적극적으로 제어권을 넘겨줍니다. 轻量级的线程非抢占式多任务处理,由协程主动交出控制权

线程大家应该都知道是可以被操作系统在任何时候进行切换,所以说线程就是抢占式多任务处理,线程是没有控制权,哪怕是一个语句执行到一半都会被操作系统切掉,然后转到其它线程去操作。

那么反之对于协程来说,什么时候交出控制权,什么时候不交出控制权是由协程内部主动决定的,正是因为这种非抢占式,所以被称之为轻量级。

并且多个协程是可以在一个或多个线程上运行的

스레드는 언제든지 운영 체제에 의해 전환될 수 있으므로 스레드는 제어할 수 없습니다. 명령문이 중간에 실행되더라도 운영 체제에 의해 끊어집니다. 작동하려면 다른 스레드로 이동하세요.

반대로 코루틴의 경우 제어권을 넘겨줄 시점과 넘겨주지 않을 시점이 코루틴에 의해 적극적으로 결정되는 것은 바로 이러한 비선점형 스타일 때문입니다.
🎜🎜🎜and여러 코루틴은 하나 이상의 스레드에서 실행될 수 있습니다. 🎜🎜🎜🎜🎜🎜2.채널🎜🎜

첫 번째 섹션에서 우리는 Go에서 많은 고루틴을 열 수 있다는 것을 배웠고, 고루틴 사이의 양방향 채널은 채널

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

기본 사용법

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

위 사례에서 볼 수 있듯이 make 기능을 사용하여 직접 채널을 생성할 수 있습니다.

7번째와 8번째 라인은 채널에 데이터를 보내는 라인입니다.

그럼 이 사건은 실행될 수 있을까요? 와서 시험해 보세요

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

이때 오류가 보고된 것을 볼 수 있습니다. 해당 오류는 채널에 1을 보낼 때 교착 상태가 발생한다는 의미입니다.

그런 다음 이전 사진으로 돌아갑니다.

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

위에서 말했듯이 채널은 고루틴과 고루틴 간의 상호 작용입니다.

하지만 이 경우에는 고루틴이 하나뿐이므로 이를 수신하려면 또 다른 고루틴이 필요합니다.

이제 고루틴을 시작하는 방법을 알아야 합니다.

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

위 그림에서는 또 다른 고루틴을 새로 오픈한 후, 무한 루프를 이용해 채널에서 보낸 값을 받아 출력해봤습니다.

하지만 채널에 두 개의 데이터를 보냈는데, 현재 인쇄 결과에는 한 개의 데이터만 있는 것을 볼 수 있습니다. 하지만 우리가 시작한 것보다 낫습니다. 그렇죠!

그러면 왜 이런 일이 일어나는 걸까요?

코드의 실행 흐름을 이해할 수 있습니다. 먼저 1이 채널로 전송된 다음 루프에서 첫 번째 값을 얻어 인쇄됩니다.

데이터 2를 채널에 다시 보내지만 인쇄하기 직전에 종료하여 데이터 1만 표시되고 데이터 2는 표시되지 않는 현상이 발생합니다.

Kaka의 설명을 통해 이 문제를 해결하는 방법을 이미 알고 계실 것입니다.

channelDome 함수에 지연된 종료 시간을 추가하는 것입니다.

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

채널을 매개변수로 전달

위에서 볼 수 있듯이 go 뒤에는 클로저 함수가 오고 이 클로저에 사용된 c는 c에서 사용된 외부 레이어입니다.

그렇다면 매개변수를 사용하여 이 c를 전달하는 것이 가능한가요? 대답은 '예'입니다.

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

물론 다른 매개변수도 전달할 수 있습니다

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

위 그림을 보면 채널뿐만 아니라 id 매개변수도 전달됨과 동시에 코드를 포함된 부분에 직접 최적화할 수도 있습니다. 즉, 값은 다음과 같습니다. 채널에서 직접 가져왔습니다.

다중 채널 만들기

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

위 그림에서 볼 수 있듯이 모두가 자신의 채널을 갖고 배포한 후 각자가 받은 가치를 받아 인쇄하게 됩니다. 밖으로.

마찬가지로 채널에 데이터를 보내기 위해 26번째 줄에 새로운 for 루프를 추가한 것을 볼 수 있습니다.

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

실행 결과를 보면, receive i와 receive I 두 값이 나오는 등 인쇄 순서가 헷갈리는 것을 알 수 있습니다.

이때, 저희가 채널에 데이터를 보내면 순서대로 보내주는게 좀 의심되시죠? 그러면 수신 시 순서대로 수신되어야 합니다.

데이터가 순서대로 전송된다고 확신하므로 문제는 Printf에서만 발생할 수 있습니다.

Printf는 IO가 있고 고루틴으로 스케줄링되어 있기 때문에 이때 Printf는 고장나지만 수신된 값이 하나씩 출력됩니다.

채널을 반환 값으로 사용

이전 섹션의 사례는 모두 채널별로 생성된 다음 매개 변수로 전달되었습니다.

이 섹션에서는 채널을 반환 값으로 반환합니다.

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

소스 코드

package mainimport (
	"fmt"
	"time")func createWorker(id int) chan int {
	c := make(chan int)
	go func() {
		for {
			fmt.Printf("Worker %d receive %c\n", id, 

여기서 보면 작업자 함수를 createWorker 함수로 변경한 것을 볼 수 있습니다. 이 함수에서는 채널이 직접 생성되기 때문입니다.

그런 다음 채널에서 받은 값이 코루틴을 통해 인쇄됩니다.

채널을 복귀합니다.

실행 결과를 살펴보겠습니다

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

실행 결과를 보면 우리의 코드 작성이 여전히 올바른 것을 알 수 있지만, 이때 반환된 채널을 매우 직관적으로 사용하는 방법을 알 수 있습니다

하지만 코드가 많으면 알 수 없습니다. 이 채널을 사용하는 방법 이 모든 코드를 사용하면 간단히 수정하면 됩니다.

그럼 해야 할 일은 외부 사람들에게 사용법을 알려주는 것입니다. ㅋㅋㅋ

그래서 현재 코드는 createWorker 메서드의 반환 값 채널 방향을 직접 표시합니다. 데이터를 보내는 기능입니다.

그러면 인쇄하면 영수증이 나오는데, 굉장히 직관적이네요.

위의 두 단계를 수정한 후 createWorker调用是报错了,Cannot use 'createWorker(i)' (type chan오류를 보면 두 유형이 동일하지 않다는 것을 알 수 있습니다.

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

수정 후에는 컴파일이 정확하고 오류 메시지가 보고되지 않는 것을 확인할 수 있습니다.

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)也是ok的。

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

本小节源码

package mainimport (
	"fmt"
	"time")func createWorker(id int) chan

buffer channel

学习了这么久了,那么咔咔问你一个问题,这段代码执行会发生什么?

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

예, 기사 시작 부분에서 언급한 것처럼 채널에 데이터를 보내려면 데이터를 받기 위해 다른 코루틴을 열어야 하기 때문에 오류가 발생합니다.

코루틴은 가볍다고 하지만 데이터를 보내면 데이터를 받기 위해 코루틴을 전환해야 하는데 이는 매우 리소스 집약적입니다.

이번 섹션에서는 이에 대해 설명하겠습니다.

buffer channel

3개의 버퍼를 가질 수 있는 채널을 만든 다음 3개의 데이터를 해당 채널로 보냅니다.

그것이 일어나지 않는다는 것을 동시에 실행한 결과에서도 알 수 있습니다deadlock.

질문입니다. 데이터 4를 버퍼에 보내면 어떻게 되나요?

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

똑똑하시군요, 결과도 생각해 보셨을 텐데요, 응, 신고해 주세요deadlock

그럼 이전 워커를 이용해서 채널 데이터를 받아보겠습니다.

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

하지만 실행 결과는 여전히 전송된 1,2,3,4가 인쇄되지 않는 것을 볼 수 있습니다.

이 질문은 지금 여러 번 질문을 받고 있으며 이 상황을 어떻게 해결해야 하는지 자문해 볼 수 있습니다.

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

지연 시간만 추가하세요. 그런데, 이전 사례에서는 문자와 모든 서식이 %c로 인쇄되었다고 설명하겠습니다. 이제는 숫자로 인쇄되므로 변경하세요. %d의 경우 약간의 변화가 있습니다. .

이런 방식으로 채널을 구축하면 성과 향상에 일정한 효과가 있습니다.

지금까지 채널이 언제 발송되었는지 알 수 없는 문제를 발견하셨나요?

다음에는 이 문제를 살펴보겠습니다.

채널 폐쇄

이전 사례의 코드를 빌려 설명을 이어갑니다.

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)
이전 코드와 일치하지 않는 점은 마지막에 close를 추가했다는 것입니다. close는 발신자에서 닫힙니다.

1,2,3,4가 수신되었음에도 불구하고 실행 결과가 만족스럽지 않음을 알 수 있습니다.

근데 아래에는 0이 많이 수신됐는데, 스크린샷에는 데이터가 한 개만 캡쳐되어 있습니다.

발신자가 채널을 닫아도 작업자는 채널이 닫혀도 데이터를 계속 수신할 수 있습니다. 그렇다고 채널이 닫힌 후에도 데이터가 수신되지 않는다는 의미는 아닙니다.

하지만 송신자가 채널을 닫도록 설정하면 수신된 데이터는 모두 0입니다. 즉, 작업자 메서드에서 전달된 c chan int 매개변수의 값은 0입니다.

이제 우리 채널은 int 유형이고 0을 받았습니다. 그러면 문자열 유형인 경우 수신되는 것은 빈 문자열입니다.

얼마나 걸리나요? 이것이 우리가 설정한 1밀리초 시간입니다.

이 프로그램을 변경하라는 요청을 받은 경우 어떤 아이디어가 있나요? 잘 모르겠으면 이 클릭의 리듬에 맞춰 흔들어 보세요.

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

함수 작업자에서는 두 가지 값을 수신하는 데 사용되며, n은 전달된 채널 c입니다. ok는 값이 존재하는지 확인하는 것입니다.

실행 결과를 볼 수 있으며, 더 이상 0개의 데이터를 받지 않게 됩니다.

이런 글쓰기 방법 외에도 더 간단한 방법이 있습니다.

Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)

배움에 대한 끈기, 쓰기에 대한 끈기, 공유에 대한 끈기 등은 카카가 창립 이래 늘 지켜온 신념입니다. 거대 인터넷에 올라온 카카의 글이 조금이나마 도움이 되었으면 좋겠습니다. 저는 카카입니다. 다음에 만나요.

위 내용은 Go의 동시 프로그래밍에 대해 이야기해 보겠습니다. (1)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.