왜 일찍 돌아오는 것이 다른 것보다 느리죠?
이것은 며칠 전에 제가 드린 답변의 후속 질문입니다.편집: 그 질문의 OP는 이미 제가 올린 코드를 사용하여 같은 질문을 하고 있었던 것 같습니다만, 저는 몰랐습니다.죄송합니다.하지만 정답은 다릅니다!
실질적으로 나는 다음과 같이 관찰했다.
>>> def without_else(param=False):
... if param:
... return 1
... return 0
>>> def with_else(param=False):
... if param:
... return 1
... else:
... return 0
>>> from timeit import Timer as T
>>> T(lambda : without_else()).repeat()
[0.3011460304260254, 0.2866089344024658, 0.2871549129486084]
>>> T(lambda : with_else()).repeat()
[0.27536892890930176, 0.2693932056427002, 0.27011704444885254]
>>> T(lambda : without_else(True)).repeat()
[0.3383951187133789, 0.32756996154785156, 0.3279120922088623]
>>> T(lambda : with_else(True)).repeat()
[0.3305950164794922, 0.32186388969421387, 0.3209099769592285]
'먹다'는 것을 있는 것else 빠릅니다.if조건이 트리거되는지 여부를 확인합니다.
두 사람이 생성하는 바이트코드가 다르다고 생각합니다만, 자세한 확인·설명을 할 수 있는 분 계십니까?
편집: 모든 사람이 제 타이밍을 재현할 수 있는 것은 아닌 것 같습니다.그래서 제 시스템에 대한 정보를 제공하는 것이 도움이 될 것 같아서요.Ubuntu 11.10 64비트를 기본 python을 설치한 상태로 실행하고 있습니다. python는 다음 합니다.
Python 2.7.2+ (default, Oct 4 2011, 20:06:09)
[GCC 4.6.1] on linux2
다음은 Python 2.7에서의 분해 결과입니다.
>>> dis.dis(without_else)
2 0 LOAD_FAST 0 (param)
3 POP_JUMP_IF_FALSE 10
3 6 LOAD_CONST 1 (1)
9 RETURN_VALUE
4 >> 10 LOAD_CONST 2 (0)
13 RETURN_VALUE
>>> dis.dis(with_else)
2 0 LOAD_FAST 0 (param)
3 POP_JUMP_IF_FALSE 10
3 6 LOAD_CONST 1 (1)
9 RETURN_VALUE
5 >> 10 LOAD_CONST 2 (0)
13 RETURN_VALUE
14 LOAD_CONST 0 (None)
17 RETURN_VALUE
이것은 단순한 추측이고, 나는 그것이 옳은지 확인하는 쉬운 방법을 알아내지 못했지만, 나는 너를 위한 이론을 가지고 있다.
같은 수 있었습니다.without_else(), 느리다, 느리다, 느리다, 느리다, 느리다, 느리다.with_else():
>>> T(lambda : without_else()).repeat()
[0.42015745017874906, 0.3188967452567226, 0.31984281521812363]
>>> T(lambda : with_else()).repeat()
[0.36009842032996175, 0.28962249392031936, 0.2927151355828528]
>>> T(lambda : without_else(True)).repeat()
[0.31709728471076915, 0.3172671387005721, 0.3285821242644147]
>>> T(lambda : with_else(True)).repeat()
[0.30939889008243426, 0.3035132258429485, 0.3046679117038593]
바이트 코드가 동일한 것을 고려하면 유일한 차이점은 함수의 이름입니다.특히 타이밍 테스트에서는 글로벌 이름을 검색합니다.을 변경해 보세요.without_else()그 차이는 사라집니다.
>>> def no_else(param=False):
if param:
return 1
return 0
>>> T(lambda : no_else()).repeat()
[0.3359846013948413, 0.29025818923918223, 0.2921801513879245]
>>> T(lambda : no_else(True)).repeat()
[0.3810395594970828, 0.2969634408842694, 0.2960104566362247]
으로는 내내 my my my my my my my mywithout_else가 globals()따라서 글로벌 이름 검색 속도가 약간 느립니다.
편집: 키가 7개 또는 8개 있는 사전에는 32개의 슬롯이 있을 수 있습니다.따라서 그 기준으로는without_else이 있습니다.__builtins__:
>>> [(k, hash(k) % 32) for k in globals().keys() ]
[('__builtins__', 8), ('with_else', 9), ('__package__', 15), ('without_else', 8), ('T', 21), ('__name__', 25), ('no_else', 28), ('__doc__', 29)]
해시의 구조를 명확히 하려면:
__builtins__해시 값을 -1196389688로 하면 테이블사이즈(32)가 작아져 테이블의 #8 슬롯에 저장됩니다.
without_else해쉬를 505688136으로 줄여서 모듈로 32를 8로 줄여서 충돌이 발생하였습니다. Python은 다음과 같이
시작점:
j = hash % 32
perturb = hash
빈 슬롯을 찾을 때까지 이 절차를 반복합니다.
j = (5*j) + 1 + perturb;
perturb >>= 5;
use j % 2**i as the next table index;
다음 지표로 사용할 수 있는 17을 제공합니다.다행히 그것은 무료이기 때문에 루프가 한 번만 반복됩니다.는 2입니다.2**i는 해시입니다.i 값 'D'에서 .j.
테이블 내의 각 프로브는 다음 중 하나를 찾을 수 있습니다.
슬롯은 비어 있습니다.이 경우 프로빙이 중지되고 값이 테이블에 없음을 알 수 있습니다.
슬롯은 사용되지 않지만 과거에 사용되었던 슬롯이며, 이 경우 위와 같이 계산된 다음 값을 사용해 보겠습니다.
슬롯이 가득 찼지만 테이블에 저장된 전체 해시 값이 찾고 있는 키의 해시 값과 같지 않습니다(이것이 다음 경우에 발생합니다).
__builtins__대without_else).슬롯이 꽉 차서 원하는 해시 값을 가지고 있으며 Python은 키와 개체가 동일한 개체인지 확인합니다(이 경우 식별자일 수 있는 짧은 문자열이 삽입되어 동일한 식별자가 동일한 문자열을 사용하기 때문입니다).
마지막으로 슬롯이 꽉 차면 해시는 정확하게 일치하지만 키가 동일한 개체가 아닙니다. 그러면 Python은 동일한 개체와 동일한지 비교합니다.이것은 비교적 느리지만, 이름 조회는 실제로 일어나지 않습니다.
언급URL : https://stackoverflow.com/questions/8271139/why-is-early-return-slower-than-else
'programing' 카테고리의 다른 글
| MariaDB 및 창 기능(또는 SQL:2003 표준 지원) (0) | 2022.11.23 |
|---|---|
| Restful API with Flask 및 MySQL 데이터베이스 with Rasberry Pi (0) | 2022.11.23 |
| 전체 MySQL 데이터베이스에 대한 모든 외부 키 제약 조건 보기 (0) | 2022.11.14 |
| Java를 사용하여 16진수 덤프의 문자열 표현을 바이트 배열로 변환하시겠습니까? (0) | 2022.11.14 |
| JavaScript에서 이메일을 보내는 방법 (0) | 2022.11.14 |