2017-10-09 15 views
1

나는 프로세스를 연기한다고 알고있다. 또한 File 및 기타 리소스를 다룰 때 사용하는 것이 좋은 것처럼 예제를 읽습니다. 내 질문은, 파이썬 등 다른 언어로 처리되지 않는 것입니까? 그렇다면 Go가 몇 가지 독특한 기능을 제공합니까?지연 기능이 Go에서 얼마나 유용하며 다른 언어에서 사용할 수있는 대체 기능은 무엇입니까?

두 가지 기능 f1f2가 말 나는 f1이 완료되면 f2를 호출합니다. 다음과 같이 할 수 있습니다.

def f1(): 
    done = False 
    print('I am doing extensive work') 
    done = True 
    return done 

def f2(): 
    print('here we go') 

if f1(): 
    f2() 

코딩 작업을 최소화하여 동일한 작업을 연기합니까?

답변

2

defer 이름에서 알 수 있듯이에 상관없이 호출 함수 본문이 종료 될 때까지 지연된 함수의 실행이 지연됩니다 (). 따라서 함수 f1 정의 f2f1 내부의 내용이 예외로 인해 실패하더라도 f2이 호출되는지 확인합니다. try/catch 블록의 finally 절로 생각합니다.

파이썬에서 내가 생각할 수있는 가장 가까운 점은 defercontext managers입니다. 내가 가장 가깝고 똑같지는 않지만 그 목적이 조금 겹쳐지기 때문에 약간은 알 수있다.

1

Go의 defer statement은 또 다른 접근 방법이며 장단점이있다. 다른 언어는 적절한 자원 종결을 처리 할 수있는 대안을 제시합니다. 예를 들어 Java는 Exceptions 및 try-catch 블록을 제공합니다. Go FAQ: Why does Go not have exceptions?

에서 인용

우리는 복잡한 코드의 결과는 try-catch-finally 관용구 같이, 제어 구조에 그 결합의 예외를 생각합니다. 또한 프로그래머가 예외적으로 파일 열기에 실패한 것과 같은 너무 많은 일반 오류를 레이블링하는 경향이 있습니다.

이동은 다른 접근 방식을 취합니다. 일반 오류 처리의 경우 Go의 다중 값 반환을 사용하면 반환 값에 과부하가 발생하지 않고 오류를 쉽게보고 할 수 있습니다. A canonical error type, coupled with Go's other features은 오류 처리를 즐겁지 만 다른 언어의 오류 처리와 상당히 다릅니다.

go에는 진정한 예외적 인 조건에서 신호를 보내고 복구 할 수있는 몇 가지 내장 기능이 있습니다. 복구 메커니즘은 오류 발생 후 함수의 상태가 해체되는 과정의 일부로 만 실행됩니다.이 상태는 재앙을 처리하기에 충분하지만 별도의 제어 구조가 필요하지 않으며 잘 사용될 경우 오류 처리 코드가 깨끗해질 수 있습니다.

자세한 내용은 Defer, Panic, and Recover 문서를 참조하십시오.

자바 try-catch 예에 비해 defer 사용의 장점은 폐쇄 또는 개방 된 리소스의 배치를 처리하는 코드는 오른쪽 옆을 연 코드 때문이다.예를 들어

:

f, err := os.Open("file.txt") 
if err != nil { 
    log.Printf("Failed to open file: %v", err) 
    return 
} 
defer f.Close() 

// f is open you may read from it 
... 

자원의 폐기 다른 언어가 다른 코드 블록으로 이동하면이 곳에 따라 열심히하고 실제로 그것을 폐기 처리했다합니다.

1

연기를 이해하려면 대안을 이해해야합니다. 많은 자원을 다루는 복잡한 코드에서

당신은이 (의사 코드) 같은 일을 결국 : 이것은 자세한 빨리 도착

mtx.Lock() 
file1, err := os.Open(...) 
if err != nil { 
    mtx.Unlock() 
    return err 
} 
conn, err := net.Dial(...) 
if err != nil { 
    file1.Close() 
    mtx.Unlock() 
    return err 
} 
file2, err := os.Open(...) 
if err != nil { 
    conn.Close() 
    file1.Close() 
    mtx.Unlock() 
    return err 
} 
do_things() 
file2.Close() 
conn.Close() 
file1.Close() 
mtx.Unlock() 
return nil 

. 또한 코드를 편집하고 file1을 열기 전에 네트워크 연결 열기를 이동하면 오류 처리 경로가 올바르게 업데이트되지 않을 수 있기 때문에 장기간에 오류가 발생하기 쉽습니다. C에서

, 여기에 공통 관용구는 함수의 끝에서 모든 리소스 정리를 수집하고이 같은 것을하는 것입니다 :

ret = ERROR; 
    lock(mtx); 
    fd1 = open(...); 
    if (fd1 == -1) 
     goto err1; 
    conn = net_conn(...); 
    if (conn == -1) 
     goto err2; 
    fd2 = open(...); 
    if (fd2 == -1) 
     goto err3; 
    do_things(); 

    ret = 0; 
    close(fd2); 
err3: 
    close(conn); 
err2: 
    close(fd1); 
err1: 
    unlock(mtx); 
    return ret; 

이 꽤 중 하나되지 않습니다 그것은이를 얻기 위해 매우 쉽게 잘못도.

은 연기와 같은 일을하고 비교 우리가 얻을으로 : 그것은 이동이 발생하고 오해 또는 미래에 침입하는 것은 매우 어려운 것을 이해합니다 알고 명확하고 간결한, 사람의

mtx.Lock() 
defer mtx.Unlock() 
file1, err := os.Open(...) 
if err != nil { 
    return err 
} 
defer file1.Close() 
conn, err := net.Dial(...) 
if err != nil { 
    return err 
} 
defer conn.Close() 
file2, err := os.Open(...) 
if err != nil { 
    return err 
} 
defer file2.Close() 
.... do things ... 
return nil 

.