programing

"x < y < z"가 "x < y and y < z"보다 빠릅니까?

newstyles 2023. 7. 23. 14:05

"x < y < z"가 "x < y and y < z"보다 빠릅니까?

페이지를 통해 우리는 다음을 알 수 있습니다.

는 연된비사것빠보릅다니를 보다 더 .and교환입니다.쓰기x < y < zx < y and y < z.

그러나 다음 코드 스니펫을 테스트하는 다른 결과를 얻었습니다.

$ python -m timeit "x = 1.2" "y = 1.3" "z = 1.8" "x < y < z"
1000000 loops, best of 3: 0.322 usec per loop
$ python -m timeit "x = 1.2" "y = 1.3" "z = 1.8" "x < y and y < z"
1000000 loops, best of 3: 0.22 usec per loop
$ python -m timeit "x = 1.2" "y = 1.3" "z = 1.1" "x < y < z"
1000000 loops, best of 3: 0.279 usec per loop
$ python -m timeit "x = 1.2" "y = 1.3" "z = 1.1" "x < y and y < z"
1000000 loops, best of 3: 0.215 usec per loop

는 것 같습니다.x < y and y < z보다 .x < y < z왜요?

사이트의 일부 게시물(이 게시물과 같은)을 검색한 결과, "한 번만 평가"가 핵심이라는 것을 알게 되었습니다.x < y < z하지만 아직도 혼란스럽습니다.추가 연구를 위해 다음을 사용하여 이 두 가지 기능을 분해했습니다.dis.dis:

import dis

def chained_compare():
        x = 1.2
        y = 1.3
        z = 1.1
        x < y < z

def and_compare():
        x = 1.2
        y = 1.3
        z = 1.1
        x < y and y < z

dis.dis(chained_compare)
dis.dis(and_compare)

출력은 다음과 같습니다.

## chained_compare ##

  4           0 LOAD_CONST               1 (1.2)
              3 STORE_FAST               0 (x)

  5           6 LOAD_CONST               2 (1.3)
              9 STORE_FAST               1 (y)

  6          12 LOAD_CONST               3 (1.1)
             15 STORE_FAST               2 (z)

  7          18 LOAD_FAST                0 (x)
             21 LOAD_FAST                1 (y)
             24 DUP_TOP
             25 ROT_THREE
             26 COMPARE_OP               0 (<)
             29 JUMP_IF_FALSE_OR_POP    41
             32 LOAD_FAST                2 (z)
             35 COMPARE_OP               0 (<)
             38 JUMP_FORWARD             2 (to 43)
        >>   41 ROT_TWO
             42 POP_TOP
        >>   43 POP_TOP
             44 LOAD_CONST               0 (None)
             47 RETURN_VALUE

## and_compare ##

 10           0 LOAD_CONST               1 (1.2)
              3 STORE_FAST               0 (x)

 11           6 LOAD_CONST               2 (1.3)
              9 STORE_FAST               1 (y)

 12          12 LOAD_CONST               3 (1.1)
             15 STORE_FAST               2 (z)

 13          18 LOAD_FAST                0 (x)
             21 LOAD_FAST                1 (y)
             24 COMPARE_OP               0 (<)
             27 JUMP_IF_FALSE_OR_POP    39
             30 LOAD_FAST                1 (y)
             33 LOAD_FAST                2 (z)
             36 COMPARE_OP               0 (<)
        >>   39 POP_TOP
             40 LOAD_CONST               0 (None)

보아하니..x < y and y < z에는 보분 해된수 적습니다가명령보다 가 덜 되어 있습니다.x < y < z고려해 봐야 할까요?x < y and y < z보다 빠른.x < y < z?

Intel(R) Xeon(R) CPU E5640 @ 2.67GHz에서 Python 2.7.6으로 테스트되었습니다.

은 점은차이에서x < y < z y한 번만 평가됩니다.이는 y가 변수인 경우에는 큰 차이가 없지만 계산에 시간이 걸리는 함수 호출인 경우에는 큰 차이가 없습니다.

from time import sleep
def y():
    sleep(.2)
    return 1.3
%timeit 1.2 < y() < 1.8
10 loops, best of 3: 203 ms per loop
%timeit 1.2 < y() and y() < 1.8
1 loops, best of 3: 405 ms per loop

당신이 정의한 두 기능 모두에 대한 최적의 바이트코드는 다음과 같다.

          0 LOAD_CONST               0 (None)
          3 RETURN_VALUE

비교 결과가 사용되지 않기 때문입니다.비교 결과를 반환하여 상황을 더 흥미롭게 만들어 보겠습니다.또한 컴파일 시 결과를 알 수 없도록 합니다.

def interesting_compare(y):
    x = 1.1
    z = 1.3
    return x < y < z  # or: x < y and y < z

다시 말하지만, 비교의 두 버전은 의미적으로 동일하므로 최적의 바이트 코드는 두 구성 모두에 대해 동일합니다.제가 할 수 있는 한, 이렇게 보일 것입니다.각 라인에 각 opcode 전후의 스택 내용을 Forth 표기(오른쪽 스택 맨 위,--, 뒤에 앞로나기누, 행후뒤?있을 수도 있고 없을 수도 있음을 나타냅니다.:RETURN_VALUE반환된 값 아래 스택에 남아 있는 모든 항목을 삭제합니다.

          0 LOAD_FAST                0 (y)    ;          -- y
          3 DUP_TOP                           ; y        -- y y
          4 LOAD_CONST               0 (1.1)  ; y y      -- y y 1.1
          7 COMPARE_OP               4 (>)    ; y y 1.1  -- y pred
         10 JUMP_IF_FALSE_OR_POP     19       ; y pred   -- y
         13 LOAD_CONST               1 (1.3)  ; y        -- y 1.3
         16 COMPARE_OP               0 (<)    ; y 1.3    -- pred
     >>  19 RETURN_VALUE                      ; y? pred  --

CPython, PyPy 등의 언어 구현이 두 변형 모두에 대해 이 바이트 코드(또는 해당하는 작업 시퀀스)를 생성하지 않으면 해당 바이트 코드 컴파일러의 품질이 저하됩니다.위에 게시한 바이트코드 시퀀스에서 얻는 것은 해결된 문제입니다. (이 경우에 필요한 것은 지속적접기, 데드 코드 제거, 스택 내용의 더 나은 모델링뿐이라고 생각합니다. 공통적인 하위 표현 제거 또한 저렴하고 가치가 있습니다.)그리고 현대 언어 구현에서 그것을 하지 않는 것에는 정말 변명의 여지가 없습니다.

현재 이 언어의 모든 구현에는 품질이 낮은 바이트 코드 컴파일러가 있습니다.하지만 여러분은 코딩을 하는 동안 그것을 무시해야 합니다!바이트코드 컴파일러가 정상인 것처럼 가장하고 가장 읽기 쉬운 코드를 작성합니다.어쨌든 충분히 빠를 것입니다.그렇지 않다면 먼저 알고리즘 개선을 찾고 Cython에게 두 번째 시도를 하십시오. 동일한 노력에 대해 적용할 수 있는 표현 수준 수정보다 훨씬 더 많은 개선을 제공할 것입니다.

출력의 차이는 최적화가 부족하기 때문에 대부분의 경우 이 차이를 무시해야 한다고 생각합니다. 차이가 사라질 수 있습니다.다른 점은y한 번만 평가해야 하며 추가가 필요한 스택에서 복제하여 해결해야 합니다.POP_TOP을 사용하는 LOAD_FAST하지만 가능할지도 모릅니다.

은 하만중차은점이한요지▁in에 있다는 입니다.x<y and y<z의 2의y다음과 같은 경우 두 번 평가해야 합니다.x<ytrue로되며, 만약 사로평가만, 은평약가의 .y상당한 시간이 걸리거나 부작용이 있습니다.

에서는 대분의시서사합니다야용해를 .x<y<z다소 느리긴 하지만 말입니다.

우선, 성능 향상을 제공하기 위해 두 개의 서로 다른 구조가 도입되지 않았기 때문에 비교가 거의 의미가 없으므로 이를 기준으로 다른 구조를 대신 사용할지 여부를 결정해서는 안 됩니다.

x < y < z구성:

  1. 의미가 더 명확하고 직접적입니다.
  2. 그것의 의미는 비교의 "수학적 의미"에서 기대되는 것입니다: 평가.x,y그리고.z 전체 상태가 유지되는지 확인합니다.사용.and평가를 통해 의미론을 변경합니다.y결과를 변경할 수 있습니다.

따라서 원하는 의미론과 동일한 의미론에 따라 다른 의미론 대신 다른 의미론을 선택합니다.

즉, 코드를 분해한다고 해서 코드가 느려지는 것은 아닙니다.그러나 더 많은 바이트코드 작업을 실행한다는 것은 각 작업이 더 간단하지만 메인 루프의 반복이 필요하다는 것을 의미합니다.즉, 수행 중인 작업이 매우 빠른 경우(예: 로컬 변수 조회) 더 많은 바이트 코드 작업을 실행하는 데 따른 오버헤드가 문제가 될 수 있습니다.

그러나 이 결과는 더 일반적인 상황에서는 유지되지 않으며 프로파일링하는 "최악의 경우"에만 적용됩니다.다른 사람들이 지적했듯이, 만약 당신이 변한다면,y시간이 조금 더 걸리는 경우, 연결된 표기법이 결과를 한 번만 평가하기 때문에 결과가 변경되는 것을 볼 수 있습니다.

요약:

  • 수행하기 전에 의미론을 고려합니다.
  • 가독성을 고려합니다.
  • 마이크로 벤치마크를 신뢰하지 마십시오.항상 다른 종류의 매개 변수로 프로파일링하여 함수/식 타이밍이 해당 매개 변수와 관련하여 어떻게 동작하는지 확인하고 이 매개 변수를 사용할 계획인지 고려합니다.

언급URL : https://stackoverflow.com/questions/34014906/is-x-y-z-faster-than-x-y-and-y-z