golang은 gofunc와 defer를 잘 사용합니다.

3175 단어 Go 개발

1. error와 panic:

  • error: 예견할 수 있는 오류
  • 패닉: 예견할 수 없는 오류입니다. 패닉은 일반적으로 defer의recover()를 통해 위험이 있는 코드를 포획합니다. 만약에 패닉이 발생하면 프로그램이 이상하게 종료됩니다. 예를 들어 수조가 경계를 넘을 수 있습니다

  • 1. 패닉의 품위

  • 패닉은 질서가 있습니다. 탈퇴하기 전에 현재 goroutine에서 이미 defer[걸기]를 처리한 임무를 수행합니다. 만약에 어떤 defer가 패닉 후에 실행되지 않습니다..
  • panic는 현재 goroutine 아래의 defer만 모두 조정될 것을 보증하지만 다른 협의의 defer도 조정될 것을 보증하지 않는다
  • 같은 goroutine 아래에 이미 걸려 있는 여러 개의 defer를 거슬러 올라가 집행한다. 즉, 선진적인 후출이다

  • 예:
    func main() {
    	defer fmt.Println("defer main") 
    	var user = os.Getenv("USER_")
    	go func() {
    		defer fmt.Println("defer caller")
    		func() {
    			defer func() {
    				fmt.Println("defer here")
    			}()
    
    			if user == "" {
    				panic("should set user env.")
    			}
    		}()
    	}()
    
    	time.Sleep(1 * time.Second)
    	fmt.Printf("get result")
    }
    
    //result:
    defer here
    defer caller
    panic: should set user env.
    
    func main() {
    	defer fmt.Println("defer main") 
    	var user = os.Getenv("USER_")
    	go func() {
    		defer fmt.Println("defer caller")
    		func() {
    
    			if user == "" {
    				panic("should set user env.")
    			}
    
    			defer func() {//panic , , 
    				fmt.Println("defer here")
    			}()
    		}()
    	}()
    
    	time.Sleep(1 * time.Second)
    	fmt.Printf("get result")
    }
    
    //result:
    defer caller
    panic: should set user env.
    
    

    2. 패닉의 처리: defer+recover

  • defer에서 리커버를 통해 패닉을 캡처하여 유사try_catch 효과.
  • defer는 반환 전이나 패닉 후에 실행됩니다
  • 
    	defer func() {
    		err := recover()
    		if err != nil {//recover , panic 
    			var errMsg, logMsg string
    			switch err.(type) {
    			case *global.FlyWebError: //web error
    				webErr := err.(*global.FlyWebError)
    				code = webErr.Code
    				errMsg = util.GetErrMsgByCode(code)
    				logMsg = webErr.Msg
    			default: // 
    				code = util.ERRCODE_UNKNOWN
    				errMsg = util.GetErrMsgByCode(code)
    				logMsg = fmt.Sprint(err)
    			}
    			log.Error(common.LOG_CMD, logMsg, 0, 0, 0)
    		}
    	}()
    

    2. gofunc()와panic


    gofunc () 는 익명 함수 내의 논리를 실행하기 위해 하위 협정을 실행합니다.
  • 그러나 메인 프로세스의 defer는 하위 협정의 패닉 이상을 포획할 수 없기 때문에 gofunc()에서는 일반적으로 defer()가 이 하위 협정에서 발생하는 패닉을 처리한다

  • func () + defer는 일반적으로 다음과 같은 용도로 사용됩니다. 원격 호출을 여러 번 하고, 매번 새로운 협정을 열어 실행합니다. 결과를 기다리지 않고 다음 번을 순환할 수 있습니다. 예를 들어
        wg := sync.WaitGroup{}
        wg.Add(len(arrCommentIds))
    	for i := 0; i < len(arrCommentIds); i++ {
    		go func(commentId []string) {
    			defer func() {
    				wg.Done()
    				if err0 := recover(); err0 != nil {
    					err = errors.New(fmt.Sprint(err0))
    				}
    			}()
    			var tempCommentList *centerpb.CommentList
    			tempCommentList, err = rpc.GetCommentInfo(commentId, targetId, filter)
    			if err != nil {
    				return
    			}
    			mutex.Lock()
    			commentList.Comments = append(commentList.Comments, tempCommentList.Comments...)
    			mutex.Unlock()
    		}(arrCommentIds[i])
    	}
    	wg.Wait()// 
    
    

    그래서 defer의 용도는 일반적으로 다음과 같다.
  • 이상 포획
  • 반드시 실행해야 할 논리를 봉인하고 순서대로 실행할 때 앞의 코드가 리턴되어 이 줄의 논리를 잊어버릴까 봐 걱정합니다.예를 들면 자물쇠의 방출..

  • defer를 사용하는 것은 대가가 있기 때문에 cpu의 낭비를 초래할 수 있으므로 합리적으로 사용해야 한다.

    좋은 웹페이지 즐겨찾기