Writing Fast Code (KR)

Preview:

Citation preview

PureEducation : https://youtu.be/_IVqMXPFYwI

WRITING FAST CODE파이콘 한국 2015 김영근 (@scari_net)

발표자 소개

• 김영근 a.k.a. scari • http://younggun.kim • Badass Alien @ D9, 스마트스터디 • PyCon KR Organizer • PyCon US 2015 Session Staff

내가 생각하는 내 코드의 실행 속도

영화 놈놈놈

실제 실행 속도

The Killers : All These Things That I’ve Done M/V https://youtu.be/sZTpLvsYYHw

목표

• 컴퓨터와 파이썬의 내부 이해하기

• 프로파일링으로 핫스팟 찾기

• 개선 -> 빠른 코드!

진짜 목표

• 빠르면서도 느린 컴퓨터

• 잘 모르겠지만 프로파일링은 좋은 녀석

• 나도 빠른 코드 짜고 싶다.

근데 왜? Why?

10만명이 사용하는 코드의 성능을 1초만 개선하면

10만초 -> 하루하고도 3시간 46분 40초 절약

인류가 낭비하는 시간 절약!

발표 순서 TOC

컴퓨터의 동작 원리부터

파이썬 코드가

어떻게 굴러가는지 확인

프로파일러 한 숟가락 넣고

간단한 개선 작업 후 성능 확인

WARNING

Don’t worry. I know this is PyCon.

컴퓨터의 동작 원리부터

입출력 장치 <<<넘사벽<<< 메모리

모스(Morse) 부호 Modem (2400) CDMA(2G) HSPA(3G, DL)LTE*USB 2.0802.11nUSB 3.0SATA 3.0Thunderbolt 2DDR2 1066MhzDDR3 1600Mhz

https://en.wikipedia.org/wiki/List_of_device_bit_rates

≈ 21 bps≈ 2400 bps≈ 153 kbit/s≈ 13.98 Mbit/s≈ 100 Mbit/s≈ 480 Mbit/s≈ 600 Mbit/s≈ 3 Gbit/s≈ 6 Gbit/s≈ 20 Gbit/s≈ 64 Gbit/s≈ 102.4 Gbit/s

우왕 역시 메모리 짱 빠룸!(과연...)

DDR3 1600MhzFSB 400 (old Xeon)PCI Express 3.0 (x16)QuickPath InterconnectHyperTransport 3.1L3 Cache(i7-4790X)L2 Cache(i7-4790X)

≈ 12.8 GB/s≈ 12.8 GB/s≈ 16 GB/s≈ 38.4 GB/s≈ 51.2 GB/s≈ 170 GB/s≈ 308 GB/s

오케이...

컴퓨터의 계산 방식

0 or 1

00100000001000100000000101011110

00100000001000100000000101011110opcode

addr 1

addr 2

value

MIPS32 Add Immediate instruction (ADDI)

addi $r1, $r2, 350

ClockHz (Hertz)

인스트럭션 당 하나 이상의 클럭

여러 클럭이 필요할 수도 있음

엄마가!밥 먹으면서!스마트폰!어!보지 말라고!몇 번을!말해!으휴~~~

(찰싹!)(찰싹!)(찰싹!)(찰싹!)(찰싹!)(찰싹!)(찰싹!)

(찰싹!)(찰싹!)(찰싹!)(찰싹!)

좀 더 알아보기 쉽게

1초에 찰싹 한번 = 1Hz

1초에 찰싹 한번

L1 Cache AccesL2 Cache AccessL3 Cache AccessRAM AccessSSD I/OHDD I/OInternet: Seoul to SFIPython 실행 (0.6초)Reboot (5m)

= 1Hz

3초 9초

43초6분

2-6일1-12달

12년63년

32,000년!!

거리로 환산

L1 Cache AccesL2 Cache AccessL3 Cache AccessRAM AccessSSD I/OHDD I/OInternet: SF to SeoulIPython 실행 (0.6초)Reboot (5m) 32,000년!!

내 책상방 창문집 밖

지하철 역걸어서 부산까지

걸어서 인천-런던 왕복명왕성 벗어남...처녀자리 70 b안드로메다?

결국 컴퓨터가 하는 일

찰싹 찰싹 맞으며

때로는 먼 우주로부터 데이터를 가져와서

처리하는 것.

1초에 찰싹 한번 = 1Hz

그러니까 일을 덜 하면 덜 아프다..

가 아니고 빠르다.

이제 파이썬

dis

dis

아니고.

pip install dis

소스 줄 번호

주소 / 명령 파이썬 코드

인자

간단한 list dis질

빈 리스트 생성

[] vs list()

import dis

def create_empty_list(): return list()

def create_empty_list2(): return []

print('list()')dis.dis(create_empty_list)print('[]')dis.dis(create_empty_list2)

아이템 찾기

import disdef find_x(x, my_list): for elem in my_list: if x == elem: return True

def find_x2(x, my_list): if x in my_list: return True

print('find_x()')dis.dis(find_x)print('find_x2()')dis.dis(find_x2)

어떻게 동작하는지는 오케이.그럼 얼마나 걸리는지는?각종 프로파일러

• timeit• cProfile• line_profiler• profiling

timeit

간단.

ipython 에서는 %timeit

shell에서는 python -m timeit -c “”

GC를 비활성 하므로 일반적인 상황과는 다름.

• cProfile• 오버헤드 좀 있음.

• 대신 정보량도 많음.

• python -m cProfile code.py

• profiling

• 실시간• 이흥섭님의 세션을 참고

간단한거

피보나치킨http://fibonachicken.herokuapp.com

그냥 피보나치 수열 계산

문제 1.

피보나치킨은 nth 피보나치 숫자가 아니라 n-1번째 피보나치를 찾아야 함.

즉, 입력이 nth 피보나치일때 n-1번째 피보나치를 반환하면 됨.

문제 2.

근데 입력이 피보나치 수가 아니면?

배운자의 정리에 의하면 치킨도르.. 아니 제켄도르프 정리를 적용.

필요한 함수

• 일단 피보나치 구현 fib

• 피보나치 수가 아닌지도 알아야 하니까 is_fibonacci

• 이전 피보나치 수를 알아야 하니까 prev_fibonacci

def fib(n): if n < 2: return n return fib(n-2) + fib(n-1)

def is_fibonacci_awful(n): i = 0 while True: if fib(i) == n: return True elif fib(i) > n: return False else: i += 1 continue

is_fibonacci = is_fibonacci_awful

def prev_fibonacci(n): for i in range(n-1, 0, -1): if is_fibonacci(i): return i return 0

def fibonachicken(n): if is_fibonacci(n) and n > 1: #1인 1닭 return prev_fibonacci(n)

chickens = 0 while n > 1: cfib = prev_fibonacci(n) chickens += prev_fibonacci(cfib) n -= cfib return chickens + n

(당연하지만) 왜 느릴까?

하는 일을 줄여야 한다.

이것 저것 고치고 다시

올ㅋ

아리송한 분은 Office Hour로!

근데 사실 잘 만들어 놓은 거 쓰는게 짱.

pandas에서 거저 먹은 성능 개선

import pandas as pd

intSeries = pd.Series(5, pd.date_range(start='2000-01-01', end='2000-01-08', freq='555000U'), dtype=‘int64')

timeSeries = intSeries.astype('datetime64[ns]')

%timeit intSeries.resample('1S', how='last')%timeit timeSeries.resample('1S', how='last')%prun intSeries.resample('1S', how='last')%prun timeSeries.resample('1S', how='last')

850 배

코드는?

실제 코드는 한 줄

정리

찰싹~

감사합니다

Recommended