찾다
백엔드 개발Golanggolang defer의 구현 원리를 자세히 설명하는 기사

이 글은 go 언어튜토리얼 칼럼에서 golang defer의 구현 원리를 소개한 글입니다. 도움이 필요한 친구들에게 도움이 되었으면 좋겠습니다!

defer는 golang에서 제공하는 키워드로 함수나 메소드가 실행을 완료하고 반환한 후에 호출됩니다.
각 연기는 연기 함수를 스택에 푸시합니다. 함수나 메서드가 호출되면 실행을 위해 스택에서 꺼내집니다. 따라서 여러 연기의 실행 순서는 먼저 들어와 마지막으로 나옵니다.

for i := 0; i <p><strong>defer</strong></p><p>의 트리거 타이밍은 공식 웹사이트에서 매우 명확하게 설명합니다. <br> "defer" 문은 주변 함수가 return 문을 실행했기 때문에 주변 함수가 반환되는 순간까지 실행이 연기되는 함수를 호출합니다. , 함수 본문의 끝에 도달했거나 해당 고루틴이 패닉 상태이기 때문입니다.</p><ol>
<li>defer 문에 싸인 함수가 반환될 때</li>
<li>defer 문에 싸인 함수가 끝까지 실행될 때</li>
<li>
<p>현재 고루틴 패닉</p>
<pre class="brush:php;toolbar:false">    //输出结果:return前执行defer
   func f1() {
       defer fmt.Println("return前执行defer")
       return 
   }

   //输出结果:函数执行
   // 函数执行到最后
   func f2() {
       defer fmt.Println("函数执行到最后")
       fmt.Println("函数执行")
   }

   //输出结果:panic前  第一个defer在Panic发生时执行,第二个defer在Panic之后声明,不能执行到
   func f3() {
       defer fmt.Println("panic前")
       panic("panic中")
       defer fmt.Println("panic后")
   }

defer, return, return value 실행 순서

먼저 3가지 예를 살펴보겠습니다

func f1() int { //匿名返回值
        var r int = 6
        defer func() {
                r *= 7
        }()
        return r
}

func f2() (r int) { //有名返回值
        defer func() {
                r *= 7
        }()
        return 6
}

func f3() (r int) { //有名返回值
    defer func(r int) {
        r *= 7
    }(r)
    return 6
}

f1의 실행 결과는 6, f2의 실행 결과는 42, f3의 실행 결과는 6
golang 공식 문서에 소개됨 return, defer 및 return value의 실행 순서:
주변 함수가 명시적인 return 문을 통해 반환하는 경우 deferred 함수는 해당 return 문에 의해 결과 매개 변수가 설정된 후 함수가 실행되기 전에 실행됩니다.

1. 먼저 반환 값에 값을 할당합니다
2. defer 문을 실행합니다
3. 함수 반환 반환

f1의 결과는 6입니다. f1은 익명 반환 값입니다. 익명 반환 값은 return이 실행될 때 선언되므로 defer가 선언되면 익명 반환 값에 접근할 수 없습니다.
f2는 먼저 반환 값 r, r=6을 할당하고 defer 문을 실행하고 defer를 r, r = 42로 수정한 다음 함수가 반환됩니다.
f3은 명명된 반환 값이지만 r이 defer의 매개 변수로 사용되기 때문에 defer를 선언할 때 매개 변수가 복사되어 전달되므로 defer는 defer 함수의 로컬 매개 변수에만 영향을 미치고 defer의 반환에는 영향을 주지 않습니다. 함수를 호출합니다.

클로저 및 익명 함수
익명 함수: 함수 이름이 없는 함수입니다.
클로저: 다른 함수 범위 내에서 변수를 사용할 수 있는 함수입니다.

for i := 0; i <p><strong>defer 소스 코드 분석</strong><br>defer 구현 소스 코드는 Runtime.deferproc에 있습니다<br>그런 다음 함수가 반환되기 전에 Runtime.deferreturn 함수를 실행하세요. <br>먼저 defer 구조를 이해하세요. </p><pre class="brush:php;toolbar:false">    type _defer struct {
            siz     int32 
            started bool
            sp      uintptr // sp at time of defer
            pc      uintptr
            fn      *funcval
            _panic  *_panic // panic that is running defer
            link    *_defer
    }

sp와 pc는 각각 호출자의 스택 포인터와 프로그램 카운터를 가리키고, fn은 defer 키워드에 전달된 함수이고 Panic은 defer가 실행되도록 하는 Panic입니다.
defer 키워드가 발견될 때마다 defer 함수는 런타임으로 변환됩니다.deferproc
deferproc는 newdefer를 통해 지연 함수를 생성하고 이 새로운 지연 함수를 현재 고루틴의 _defer 연결 목록에 정지시킵니다.

    func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
            sp := getcallersp()
            argp := uintptr(unsafe.Pointer(&fn)) + unsafe.Sizeof(fn)
            callerpc := getcallerpc()

            d := newdefer(siz)
            if d._panic != nil {
                    throw("deferproc: d.panic != nil after newdefer")
            }
            d.fn = fn
            d.pc = callerpc
            d.sp = sp
            switch siz {
            case 0:
                    // Do nothing.
            case sys.PtrSize:
                    *(*uintptr)(deferArgs(d)) = *(*uintptr)(unsafe.Pointer(argp))
            default:
                    memmove(deferArgs(d), unsafe.Pointer(argp), uintptr(siz))
            }
            return0()
    }

newdefer는 먼저 sched의 _defer 구조 및 현재 p의 deferpool deferpool에 _defer가 없으면 새 _defer를 초기화합니다.
_defer는 현재 g와 연관되어 있으므로 defer는 현재 g에 대해서만 유효합니다.
d.link = gp._defer
gp._defer = d //연결된 목록을 사용하여 현재 g의 모든 defer를 연결

    func newdefer(siz int32) *_defer {
            var d *_defer
            sc := deferclass(uintptr(siz))
            gp := getg()
            if sc  0 {
                            d = pp.deferpool[sc][n-1]
                            pp.deferpool[sc][n-1] = nil
                            pp.deferpool[sc] = pp.deferpool[sc][:n-1]
                    }
            }
            ......
            d.siz = siz
            d.link = gp._defer
            gp._defer = d
            return d
    }

deferreturn 현재 g에서 _defer 연결 목록을 꺼내어 실행합니다. 각 _defer는 freedefer를 호출합니다. _defer 구조를 해제하고 _defer 구조를 현재 p의 deferpool에 넣습니다.

defer 성능 분석
defer는 개발 중 리소스 릴리스, 패닉 캡처 등에 매우 유용합니다. 일부 개발자는 프로그램 성능에 대한 연기 및 프로그램의 남용 연기에 대한 영향을 고려하지 않았을 가능성이 있습니다.
성능 테스트에서는 연기가 여전히 성능에 어느 정도 영향을 미치는 것으로 나타났습니다. Yuchen의 Go 성능 최적화 팁 4/1에는 defer 문으로 인해 발생하는 추가 오버헤드에 대한 몇 가지 테스트가 있습니다.

테스트 코드

    var mu sync.Mutex
    func noDeferLock() {
        mu.Lock()
        mu.Unlock()
    }   

    func deferLock() {
        mu.Lock()
        defer mu.Unlock()
    }          
    
    func BenchmarkNoDefer(b *testing.B) {
        for i := 0; i <p><strong>테스트 결과: </strong></p><pre class="brush:php;toolbar:false">    BenchmarkNoDefer-4      100000000               11.1 ns/op
    BenchmarkDefer-4        36367237                33.1 ns/op

이전 소스 코드 분석을 통해 defer는 먼저 deferproc을 호출하여 매개 변수를 복사하고 deferreturn도 관련 정보를 추출하여 실행을 지연한다는 것을 알 수 있습니다. 명세서를 직접 호출하는 것이 더 비쌉니다.

defer의 성능은 높지 않습니다. 각 defer가 한 func에서 여러 번 발생하면 성능 소모는 20ns*n이 됩니다.

해결 방법: 예외 캡처가 필요한 경우를 제외하고 다른 자원 재활용 연기에는 defer를 사용해야 합니다. 실패를 판단한 후 goto를 사용하여 자원 재활용 코드 영역으로 이동할 수 있습니다. 경쟁적인 자원의 경우, 사용 후 즉시 자원을 해제할 수 있으므로 경쟁적인 자원을 최적으로 사용할 수 있습니다.

더 많은 golang 관련 지식을 알고 싶다면 golang튜토리얼 칼럼을 방문해주세요!

위 내용은 golang defer의 구현 원리를 자세히 설명하는 기사의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
이 기사는 segmentfault에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
C와 Golang : 성능이 중요 할 때C와 Golang : 성능이 중요 할 때Apr 13, 2025 am 12:11 AM

C는 하드웨어 리소스 및 고성능 최적화가 직접 제어되는 시나리오에 더 적합하지만 Golang은 빠른 개발 및 높은 동시성 처리가 필요한 시나리오에 더 적합합니다. 1.C의 장점은 게임 개발과 같은 고성능 요구에 적합한 하드웨어 특성 및 높은 최적화 기능에 가깝습니다. 2. Golang의 장점은 간결한 구문 및 자연 동시성 지원에 있으며, 이는 동시성 서비스 개발에 적합합니다.

Golang in Action : 실제 예제 및 응용 프로그램Golang in Action : 실제 예제 및 응용 프로그램Apr 12, 2025 am 12:11 AM

Golang은 실제 응용 분야에서 탁월하며 단순성, 효율성 및 동시성으로 유명합니다. 1) 동시 프로그래밍은 Goroutines 및 채널을 통해 구현됩니다. 2) Flexible Code는 인터페이스 및 다형성을 사용하여 작성됩니다. 3) NET/HTTP 패키지로 네트워크 프로그래밍 단순화, 4) 효율적인 동시 크롤러 구축, 5) 도구 및 모범 사례를 통해 디버깅 및 최적화.

Golang : Go 프로그래밍 언어가 설명되었습니다Golang : Go 프로그래밍 언어가 설명되었습니다Apr 10, 2025 am 11:18 AM

GO의 핵심 기능에는 쓰레기 수집, 정적 연결 및 동시성 지원이 포함됩니다. 1. Go Language의 동시성 모델은 고루틴 및 채널을 통한 효율적인 동시 프로그래밍을 실현합니다. 2. 인터페이스 및 다형성은 인터페이스 방법을 통해 구현되므로 서로 다른 유형을 통일 된 방식으로 처리 할 수 ​​있습니다. 3. 기본 사용법은 기능 정의 및 호출의 효율성을 보여줍니다. 4. 고급 사용에서 슬라이스는 동적 크기 조정의 강력한 기능을 제공합니다. 5. 레이스 조건과 같은 일반적인 오류는 Getest-race를 통해 감지 및 해결할 수 있습니다. 6. 성능 최적화는 sync.pool을 통해 개체를 재사용하여 쓰레기 수집 압력을 줄입니다.

Golang의 목적 : 효율적이고 확장 가능한 시스템 구축Golang의 목적 : 효율적이고 확장 가능한 시스템 구축Apr 09, 2025 pm 05:17 PM

Go Language는 효율적이고 확장 가능한 시스템을 구축하는 데 잘 작동합니다. 장점은 다음과 같습니다. 1. 고성능 : 기계 코드로 컴파일, 빠른 달리기 속도; 2. 동시 프로그래밍 : 고어 라틴 및 채널을 통한 멀티 태스킹 단순화; 3. 단순성 : 간결한 구문, 학습 및 유지 보수 비용 절감; 4. 크로스 플랫폼 : 크로스 플랫폼 컴파일, 쉬운 배포를 지원합니다.

SQL 분류의 진술에 의한 순서 결과가 때때로 무작위로 보이는 이유는 무엇입니까?SQL 분류의 진술에 의한 순서 결과가 때때로 무작위로 보이는 이유는 무엇입니까?Apr 02, 2025 pm 05:24 PM

SQL 쿼리 결과의 정렬에 대해 혼란스러워합니다. SQL을 학습하는 과정에서 종종 혼란스러운 문제가 발생합니다. 최근 저자는 "Mick-SQL 기본 사항"을 읽고 있습니다.

기술 스택 컨버전스는 기술 스택 선택의 프로세스 일뿐입니까?기술 스택 컨버전스는 기술 스택 선택의 프로세스 일뿐입니까?Apr 02, 2025 pm 05:21 PM

기술 스택 컨버전스와 기술 선택의 관계, 소프트웨어 개발에서 기술 스택의 선택 및 관리는 매우 중요한 문제입니다. 최근에 일부 독자들은 ...

반사 비교를 사용하고 GO의 세 구조의 차이점을 처리하는 방법은 무엇입니까?반사 비교를 사용하고 GO의 세 구조의 차이점을 처리하는 방법은 무엇입니까?Apr 02, 2025 pm 05:15 PM

GO 언어로 세 가지 구조를 비교하고 처리하는 방법. GO 프로그래밍에서는 때때로 두 구조의 차이점을 비교하고 이러한 차이점을 ...에 적용해야합니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
4 몇 주 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

mPDF

mPDF

mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.

SecList

SecList

SecLists는 최고의 보안 테스터의 동반자입니다. 보안 평가 시 자주 사용되는 다양한 유형의 목록을 한 곳에 모아 놓은 것입니다. SecLists는 보안 테스터에게 필요할 수 있는 모든 목록을 편리하게 제공하여 보안 테스트를 더욱 효율적이고 생산적으로 만드는 데 도움이 됩니다. 목록 유형에는 사용자 이름, 비밀번호, URL, 퍼징 페이로드, 민감한 데이터 패턴, 웹 셸 등이 포함됩니다. 테스터는 이 저장소를 새로운 테스트 시스템으로 간단히 가져올 수 있으며 필요한 모든 유형의 목록에 액세스할 수 있습니다.

에디트플러스 중국어 크랙 버전

에디트플러스 중국어 크랙 버전

작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

SublimeText3 Linux 새 버전

SublimeText3 Linux 새 버전

SublimeText3 Linux 최신 버전

Dreamweaver Mac版

Dreamweaver Mac版

시각적 웹 개발 도구