IP ์นด๋ฉ๋ผ์์ ์ฃผ๊ธฐ์ ์ผ๋ก ์ด๋ฏธ์ง๋ฅผ ๊ฒ์ํ๋ ๋งค์ฐ ๊ฐ๋จํ ํ๋ก๊ทธ๋จ์ด ์์ต๋๋ค. ์ด ํ๋ก๊ทธ๋จ์ ์์ ์ธํธ๊ฐ ๋จ์กฐ๋กญ๊ฒ ์ฆ๊ฐํ๋ค๋ ๊ฒ์ ์์ ์ฐจ ๋ ธ์ต๋๋ค. ๋ฌธ์ ๋ฅผ ์ฌํํ๋ ์์ ํ๋ก๊ทธ๋จ์ ์์ฑํ์ต๋๋ค.
import requests
from memory_profiler import profile
<strong i="6">@profile</strong>
def lol():
print "sending request"
r = requests.get('http://cachefly.cachefly.net/10mb.test')
print "reading.."
with open("test.dat", "wb") as f:
f.write(r.content)
print "Finished..."
if __name__=="__main__":
for i in xrange(100):
print "Iteration", i
lol()
๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ๊ฐ ๋ฐ๋ณต์ด ๋๋ ๋ ์ธ์๋ฉ๋๋ค. ์ด๊ฒ์ ์ํ ์ถ๋ ฅ์
๋๋ค.
* ๋ฐ๋ณต 0 *
Iteration 0
sending request
reading..
Finished...
Filename: test.py
Line # Mem usage Increment Line Contents
================================================
5 12.5 MiB 0.0 MiB <strong i="12">@profile</strong>
6 def lol():
7 12.5 MiB 0.0 MiB print "sending request"
8 35.6 MiB 23.1 MiB r = requests.get('http://cachefly.cachefly.net/10mb.test')
9 35.6 MiB 0.0 MiB print "reading.."
10 35.6 MiB 0.0 MiB with open("test.dat", "wb") as f:
11 35.6 MiB 0.0 MiB f.write(r.content)
12 35.6 MiB 0.0 MiB print "Finished..."
* ๋ฐ๋ณต 1 *
Iteration 1
sending request
reading..
Finished...
Filename: test.py
Line # Mem usage Increment Line Contents
================================================
5 35.6 MiB 0.0 MiB <strong i="17">@profile</strong>
6 def lol():
7 35.6 MiB 0.0 MiB print "sending request"
8 36.3 MiB 0.7 MiB r = requests.get('http://cachefly.cachefly.net/10mb.test')
9 36.3 MiB 0.0 MiB print "reading.."
10 36.3 MiB 0.0 MiB with open("test.dat", "wb") as f:
11 36.3 MiB 0.0 MiB f.write(r.content)
12 36.3 MiB 0.0 MiB print "Finished..."
๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ๋ฐ๋ณต ํ ๋๋ง๋ค ์ฆ๊ฐํ์ง ์์ง๋ง requests.get
๊ฐ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ์ฆ๊ฐ์ํค๋ ์์ธ์ผ๋ก ๊ณ์ ์ฆ๊ฐํฉ๋๋ค.
** Iteration 99 **์ ์ํด ์ด๊ฒ์ ๋ฉ๋ชจ๋ฆฌ ํ๋กํ์ ๋ชจ์ต์ ๋๋ค.
Iteration 99
sending request
reading..
Finished...
Filename: test.py
Line # Mem usage Increment Line Contents
================================================
5 40.7 MiB 0.0 MiB <strong i="23">@profile</strong>
6 def lol():
7 40.7 MiB 0.0 MiB print "sending request"
8 40.7 MiB 0.0 MiB r = requests.get('http://cachefly.cachefly.net/10mb.test')
9 40.7 MiB 0.0 MiB print "reading.."
10 40.7 MiB 0.0 MiB with open("test.dat", "wb") as f:
11 40.7 MiB 0.0 MiB f.write(r.content)
12 40.7 MiB 0.0 MiB print "Finished..."
ํ๋ก๊ทธ๋จ์ด ์ข ๋ฃ๋์ง ์๋ ํ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ๋จ์ด์ง์ง ์์ต๋๋ค.
๋ฒ๊ทธ๊ฐ ์์ต๋๊น, ์๋๋ฉด ์ฌ์ฉ์ ์ค๋ฅ์ ๋๊น?
์ด ๋ฌธ์ ๋ฅผ ์ ๊ธฐํ๊ณ ์์ธํ ์ ๋ณด๋ฅผ ์ ๊ณตํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค!
๋งํด ๋ด์, ์ด๋ค ์์ ์์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๊ฐ์ํ๋ ๊ฒ์ ๋ณธ ์ ์ด ์์ต๋๊น?
๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ์ค์ด๋๋ ๊ฒ์ ๋ณด์ง ๋ชปํ์ต๋๋ค. ๋๋ ๊ทธ๊ฒ์ด ํ์ด์ฌ์ ๊ฐ๋น์ง ์์ง๊ธฐ์ ๊ด๋ จ์ด ์๋์ง ๊ถ๊ธํ๊ณ ์๋ง๋ ์์ํ ๊ธฐํ๊ฐ ์์์ ๊ฒ์ด๋ฏ๋ก ๋ค์ด๋ก๋ ํ ๋๋ง๋ค gc.collect()
์ ๋ํ ํธ์ถ์ ์ถ๊ฐํ์ต๋๋ค. ๊ทธ๊ฒ์ ์๋ฌด๋ฐ ์ฐจ์ด๊ฐ ์์์ต๋๋ค.
์ด ๋ฌธ์ ๊ฐ ์ข ๊ฒฐ ๋ ์ด์ ๋ฅผ ๋ฌผ์ด๋ด๋ ๋ ๊น์?
์ฐ๋ฆฌ ํ์ฌ๋ pypy๋ฅผ ์ฌ์ฉํ ๋ ๋์ฑ ๊ฐํ ๋ ์ด์ ๋์ผํ ๋ฌธ์ ๋ฅผ ๊ฒฝํํ์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ฝ๋๋ฒ ์ด์ค์์์ด ๋ฌธ์ ์ ์์ธ์ ํ์ด์ฌ ์์ฒญ์ผ๋ก ์ถ์ ํ๋ ๋ฐ ๋ฉฐ์น ์ ๋ณด๋์ต๋๋ค.
์ด ๋ฌธ์ ์ ์ฌ๊ฐ์ฑ์ ๊ฐ์กฐํ๊ธฐ ์ํด ๋ค์์ ๋ฉ๋ชจ๋ฆฌ ํ๋กํ์ผ ๋ฌ๋ฅผ ์คํํ ๋ ์๋ฒ ํ๋ก์ธ์ค ์ค ํ๋๊ฐ ์ด๋ป๊ฒ ์๊ฒผ๋์ง ๋ณด์ฌ์ฃผ๋ ์คํฌ๋ฆฐ ์ท์
๋๋ค.
http://cl.ly/image/3X3G2y3Y191h
์ด ๋ฌธ์ ๋ ์ผ๋ฐ cpython์์ ์ฌ์ ํ ์กด์ฌํ์ง๋ง ๋์ ๋์ง ์์ต๋๋ค. ์๋ง๋ ์ด๊ฒ์ด ์ค๋ ํ๋ก์ธ์ค์์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ์ฌ๋๋ค์๊ฒ ์ฌ๊ฐํ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ ์์์๋ ๋ถ๊ตฌํ๊ณ ์ด ๋ฌธ์ ๊ฐ๋ณด๊ณ ๋์ง ์์ ์ด์ ์ผ ๊ฒ์ ๋๋ค.
์ด ์์ ์์ ์ฐ๋ฆฌ๋ ํ์ ํ๋ก์ธ์ค์ ํจ๊ป curl์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ณ ๋ คํ ๋งํผ ์ ์คํฉ๋๋ค.
๊ทํ์ ์๊ฐ๊ณผ ์ด๊ฒ์ด ์ฒ ์ ํ ์กฐ์ฌ ๋ ๊ฒฝ์ฐ ์๋ ค์ฃผ์ญ์์ค. ๊ทธ๋ ์ง ์์ผ๋ฉด python-requests๊ฐ ๋ฏธ์ ํฌ๋ฆฌํฐ์ปฌ ์ ํ๋ฆฌ์ผ์ด์ (์ : ์๋ฃ ๊ด๋ จ ์๋น์ค)์ ์ฌ์ฉํ๊ธฐ์๋ ๋๋ฌด ์ํํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
๊ฐ์ฌ,
-๋งคํธ
ํ๋์ด ์์ด ํ์๋์์ต๋๋ค. ์ฌ๋ฐ๋ฅธ ๋ฐฉํฅ์ผ๋ก ์๋ดํ๋ ๋ฐ ์ ์ฉํ ์ง๋จ ์ ๋ณด๋ฅผ ์ ๊ณต ํ ์ ์๋ค๊ณ ์๊ฐํ์๋ฉด ๊ธฐ๊บผ์ด ๋ค์ ์ด์ด ๋๋ฆฌ๊ฒ ์ต๋๋ค.
๊ทธ๋ผ ์ ๊ฐ ๋์ ๋๋ฆฌ๊ฒ ์ต๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ์ฝ๊ฒ ์กฐ์ฌ ํ ์ ์๋๋ก ์์ git repo๋ฅผ ๋ง๋ค์์ต๋๋ค.
https://github.com/mhjohnson/memory-profiling-requests
๋ค์์ ์์ฑ๋๋ ๊ทธ๋ํ์ ์คํฌ๋ฆฐ ์ท์
๋๋ค.
http://cl.ly/image/453h1y3a2p1r
๋์์ด ๋์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค! ๋ด๊ฐ ์๋ชปํ ์ผ์ด ์์ผ๋ฉด ์๋ ค์ฃผ์ธ์.
-๋งคํธ
๊ณ ๋ง์ Matt! ์ง๊ธ๋ถํฐ ์ดํด ๋ณด๊ฒ ์ต๋๋ค. ์ฒ์ ๋ช ๋ฒ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๊ณ (๊ทธ๋ฆฌ๊ณ ๋ด๊ฐ ์๋ํ ๋ณํ) ์ด๊ฒ์ด ์ฝ๊ฒ ์ฌํ ํ ์ ์์์ ๋ณด์ฌ์ฃผ์์ต๋๋ค. ์ด์ ์ด๊ฑธ ๊ฐ์ง๊ณ ๋์์ผ ๊ฒ ์ด์.
๋ฐ๋ผ์ ์ด๊ฒ์ ์์ฒญ ๋น ์ฝ 0.1MB๋ก ์ฆ๊ฐํฉ๋๋ค. ๋ฎ์ ์์ค์ ๋ฉ์๋์ profile
๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ ค๊ณ ์๋ํ์ง๋ง ์ถ๋ ฅ์ด ์๊ฒฉ์ผ๋ก ์ ์ฉํ๊ธฐ์๋ ๋๋ฌด ๊ธธ๊ณ 0.1๋ณด๋ค ๋์ ๊ฐ๊ฒฉ์ ์ฌ์ฉํ๋ ๊ฒ์ ์ ์ฒด ์ฌ์ฉ๋์ ์ถ์ ํ๋ ๋ฐ๋ง ์ฌ์ฉ๋๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋ผ์ธ ์ฌ์ฉ. mprof๋ณด๋ค ๋ ๋์ ๋๊ตฌ๊ฐ ์์ต๋๊น?
๊ทธ๋์ ๋์ ์ถ๋ ฅ์ | ag '.*0\.[1-9]+ MiB.*'
๋ก ํ์ดํํ์ฌ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ถ๊ฐ ๋ ์ค์ ๊ฐ์ ธ์ค๊ณ profile
๋ฐ์ฝ๋ ์ดํฐ๋ฅผ Session#send
๋ก ์ฎ๊ฒผ์ต๋๋ค. ๋น์ฐํ ๋๋ถ๋ถ์ HTTPAdapter#send
ํธ์ถ์์ ๋น๋กฏ๋ฉ๋๋ค. ๋๋ ํ ๋ผ ๊ตฌ๋ฉ ์๋๋ก
์ด์ ๋ L355 ๋ฐ HTTPAdapter#get_connection
conn.urlopen
ํธ์ถ์์ ๋ชจ๋ ๋ฐ์ํฉ๋๋ค. get_connection
๊พธ๋ฏธ๋ฉด PoolManager#connection_from_url
ํธ์ถ ํ ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ 7 ๋ฒ ํ ๋นํฉ๋๋ค. ์ด์ ๋๋ค์๊ฐ urllib3์์ ๋ฐํ ๋ HTTPResponse
์ ์ํด ํธ๋ฆฌ๊ฑฐ๋๋ ๊ฒฝ์ฐ, ์ฌ์ค ์ดํ์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํด์ ๋์ง ์๋๋กํด์ผํ๋ ์ผ์ด ์๋์ง ์ดํด ๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฅผ ์ฒ๋ฆฌํ๋ ์ข์ ๋ฐฉ๋ฒ์ ์ฐพ์ ์ ์๋ค๋ฉด urllib3์ ํํค ์น๊ธฐ ์์ํ ๊ฒ์
๋๋ค.
@ sigmavirus24 ์์ฐ. ํ๋ฅญํ ์ผ! ์ฝ๋์์ ํซ์คํ์ ์ ํํ ์ฐพ์๋ธ ๊ฒ ๊ฐ์ต๋๋ค.
๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ด๋นํ๋ ๊ฐ์ฒด๋ฅผ ์ถ์ ํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด objgraph๋ฅผ ์ฌ์ฉํ์ฌ ์ถ๊ฐ ํํธ๋ฅผ ์ป์ ์ ์์ต๋๋ค.
import gc
import objgraph
# garbage collect first
gc.collect()
# print most common python types
objgraph.show_most_common_types()
Lemme๋ ๋ด๊ฐ ์ด๋ค ์ ์ผ๋ก๋ ๋์ธ ์ ์๋์ง ์๊ณ ์์ต๋๋ค.
-๋งคํธ
๋ฒ์ธ์ ๋ํ ์ฒซ ๋ฒ์งธ ์ถ์ธก์ ์์ผ ๊ฐ์ฒด์ ๋๋ค. ๊ทธ๊ฒ์ PyPy์์ ๋ ๋์ ์ด์ ๋ฅผ ์ค๋ช ํ ๊ฒ์ ๋๋ค.
๋๋ ์ง๊ธ ๊ณตํญ์ ์์ ์๊ณ ๊ณง ๋ช ์๊ฐ ๋์ ํ์ผ์์์ ๊ฒ์
๋๋ค. ๋๋ ์๋ง๋ ์ค๋ ๋ฐค ๋๋ ์ ์ฌ์ ์ผ๋ก ์ด๋ฒ ์ฃผ ํ๋ฐ๊น์ง (๋ค์ ์ฃผ๋ง / ์ฃผ๊ฐ ์๋๋ผ๋ฉด)์ด ์์
์ ์ํ ํ ์ ์์ ๊ฒ์
๋๋ค. ์ง๊ธ๊น์ง ์ฐ๋ฆฌ๊ฐ ๋๋ ค๋ฐ๋ HTTPResponse
์ release_conn
๋ฅผ ์ฌ์ฉํด ๋ณด์์ต๋๋ค. ๋๋ gc.get_referents
๋ก GC์ ์คํจ ํ ์์๋ Response ๊ฐ์ฒด๊ฐ ๋ฌด์์ธ์ง ํ์ธํ์ต๋๋ค. ์๋ณธ httplib HTTPResponse ( _original_response
๋ก ์ ์ฅ๋๊ณ get_referents
๊ฐ๋ณด๊ณ ํ ๋ด์ฉ์์)์๋ง ์ด๋ฉ์ผ ๋ฉ์์ง (ํค๋ ์ฉ) ๋ง ์๊ณ ๋๋จธ์ง๋ ๋ชจ๋ ๋ฌธ์์ด์ด๋ ์ฌ์ (๋๋ ์์ผ์ด๋ผ๋ฉด ์ด๋์์ ๊ฐ๋น์ง ์์ง๋์ง ์์์ง ์ ์ ์์ต๋๋ค.
๋ํ Session#close
(์ฝ๋์์ ๋จผ์ ๊ธฐ๋ฅ API ๋์ ์ธ์
์ ์ฌ์ฉํ๋๋กํ์ต๋๋ค)๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋์์ด๋์ง ์์ต๋๋ค (์ฐ๊ฒฐ ํ์ ์ง์ฐ๋ PoolManager๋ฅผ ์ง์์ผํฉ๋๋ค). ๊ทธ๋์ ํฅ๋ฏธ๋ก์ด ์ ์ PoolManager#connection_from_url
๊ฐ ์ฒ์ ๋ช ๋ฒ ํธ์ถ ๋ ๋ ~ 0.8MB (0.1์ ์ฃผ๊ฑฐ๋ ๊ฐ์ ธ๊ฐ๋)๋ฅผ ์ถ๊ฐํ๋ค๋ ๊ฒ์
๋๋ค. ๊ทธ๋์ ๊ทธ๊ฒ์ ~ 3MB๋ฅผ ์ถ๊ฐํ์ง๋ง ๋๋จธ์ง๋ HTTPAdapter#send
conn.urlopen
์์ ๋์ต๋๋ค. ์ด์ํ ์ ์ gc.set_debug(gc.DEBUG_LEAK)
๋ฅผ ์ฌ์ฉํ๋ฉด gc.garbage
์ ์ด์ํ ์์๊ฐ ์๋ค๋ ๊ฒ์
๋๋ค. [[[...], [...], [...], None], [[...], [...], [...], None], [[...], [...], [...], None], [[...], [...], [...], None]]
์ ๊ฐ์ ๊ฒ์ด ์๊ณ ์์๋๋ก gc.garbage[0] is gc.garbage[0][0]
์ด๋ฏ๋ก ์ ๋ณด๋ ์ ํ ์ธ๋ชจ๊ฐ ์์ต๋๋ค. ๊ธฐํ๊ฐ ์๊ธฐ๋ฉด objgraph๋ฅผ ์คํํด์ผํฉ๋๋ค.
๊ทธ๋์ ์ ๋ urllib3์ ํ๊ณ ์ค๋ ์์นจ ๋ ์ผ์ฐ ํ ๋ผ ๊ตฌ๋ฉ์ ๋ฐ๋ผ๊ฐ์ต๋๋ค. ConnectionPool#urlopen
ํ๋กํ์ ์์ฑํ์ฌ ConnectionPool#_make_request
. ์ด ์์ ์์ urllib3/connectionpool.py
306 ๋ฐ 333 ํ์์ ํ ๋น ๋ ๋ง์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์์ต๋๋ค. L306์ self._validate_conn(conn)
์ด๊ณ L333์ conn.getresponse(buffering=True)
์
๋๋ค. getresponse
๋ HTTPConnection ์ httplib
๋ฉ์๋์
๋๋ค. ๋ ์์ธํ ํ๋กํ์ผ ๋งํ๋ ๊ฒ์ ์ฝ์ง ์์ ๊ฒ์
๋๋ค. _validate_conn
๋ณด๋ฉด ์ด๊ฒ์ด ์์ธ์ด๋๋ ์ค์ ๋ค๋ฅธ HTTPConnection ๋ฉ์๋ ์ธ conn.connect()
์
๋๋ค. connect
๋ ๊ฑฐ์ ํ์คํ๊ฒ ์์ผ์ด ์์ฑ๋๋ ๊ณณ์
๋๋ค. ๋ฉ๋ชจ๋ฆฌ ํ๋กํ์ผ ๋ง์ ๋นํ์ฑํํ๊ณ print(old_pool)
์ HTTPConnectionPool#close
print(old_pool)
๋ฅผ ๋ถ์ด๋ฉด ์๋ฌด๊ฒ๋ ์ธ์๋์ง ์์ต๋๋ค. ์ธ์
์ด ํ๊ดด๋จ์ ๋ฐ๋ผ ์ค์ ๋ก ํ์ ๋ซ์ง ์๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋ด ์๊ฐ ์ ์ด๊ฒ์ด ๋ฉ๋ชจ๋ฆฌ ๋์์ ์์ธ์ด๋ผ๋ ๊ฒ์
๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ๋๋ฒ๊ทธํ๋ ๋ฐ ๋์์ ๋๋ฆฌ๊ณ ์ํฉ๋๋ค. ์ค๋๊ณผ ๋ด์ผ IRC์ ๋ค์ด์ค๊ณ ๋๊ฐ ๊ฒ์ ๋๋ค.
๋ฐ๋ผ์ ์ด๊ฒ์ ์ถ๊ฐ๋ก ์ถ์ ํ๋ฉด _make_request
์ฌ์ ํ ์ฅ์ ๋ ( profile
)์ผ๋ก python
๋ฅผ ์ด๊ณ ์ธ์
์ ์์ฑ ํ ๋ค์ 10 ์ด ๋๋ 20 ์ด๋ง๋ค ๋์ผํ URL๋), conn์ด ์ญ์ ๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผ๋์ด VerifiedHTTPSConnection
๊ฐ ๋ซํ๊ณ ์ฌ์ฌ์ฉ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ์ด๊ฒ์ connection
ํด๋์ค๊ฐ ๊ธฐ๋ณธ ์์ผ์ด ์๋๋ผ ์ฌ์ฌ์ฉ๋จ์ ์๋ฏธํฉ๋๋ค. close
๋ฉ์๋๋ httplib.HTTPConnection
(L798)์์๋ ๋ฉ์๋์
๋๋ค. ์์ผ ๊ฐ์ฒด๋ฅผ ๋ซ์ ๋ค์ None์ผ๋ก ์ค์ ํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๊ฐ์ฅ ์ต๊ทผ์ httplib.HTTPResponse
๋ซ๊ณ None์ผ๋ก ์ค์ ํฉ๋๋ค. VerifiedHTTPSConnection#connect
๋ ํ๋กํ์ผํ๋ฉด ์์ฑ / ๋์ ๋ ๋ชจ๋ ๋ฉ๋ชจ๋ฆฌ๊ฐ urllib3.util.ssl_.ssl_wrap_socket
ํฉ๋๋ค.
๋ฐ๋ผ์ ์ด๊ฒ์ ๋ณด๋ฉด memory_profiler๊ฐ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์๋ณด๊ณ ํ๋ ๋ฐ ์ฌ์ฉํ๋ ๊ฒ์ ํ๋ก์ธ์ค์ ์์ฃผ ์ธํธ ํฌ๊ธฐ (rss)์ ๋๋ค. ์ด๊ฒ์ RAM์ ํ๋ก์ธ์ค ํฌ๊ธฐ (VM ๋๋ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ํฌ๊ธฐ๋ mallocs์ ๊ด๋ จ์ด ์์)์ด๋ฏ๋ก ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋์ถ๋๋์ง ๋๋ ํ์ด์ง๊ฐ ํ ๋น๋์๋์ง ํ์ธํ๋ ค๊ณ ํฉ๋๋ค. ์ฐ๋ฆฌ๊ฐ ์์ง ์๋ ๊ธฐ์ต.
๋ฐ๋ผ์ ์ง๊ธ๊น์ง ์ฌ์ฉํ๋ ๋ชจ๋ URL์ด ํ์ธ ๋ HTTPS๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ ์ ์ ๊ฐ์ํ ๋ http://google.com
๋ฅผ ์ฌ์ฉํ๋๋ก ์ ํํ์ผ๋ฉฐ ์ฌ์ ํ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ง์์ ์ผ๋ก ์ฆ๊ฐํ๊ณ ์์ง๋ง 11-14MiB ๋ ์ ๊ฒ ์๋นํ๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ ์ฒด์ ์ผ๋ก. ์ฌ์ ํ ๋ชจ๋ ๊ฒ์ด conn.getresponse
๋ผ์ธ์ผ๋ก ๋์์ต๋๋ค (๊ทธ๋ฆฌ๊ณ ์ง๊ธ์ conn.request
).
ํฅ๋ฏธ๋ก์ด ์ ์ VMS๊ฐ repl์์ ๊ฒ์ฌ ํ ๋ ๋ง์ด ์ฑ์ฅํ์ง ์๋ ๊ฒ ๊ฐ์ต๋๋ค. RSS ๊ฐ ๋์ ํด๋น ๊ฐ์ ๋ฐํํ๋๋ก mprof๋ฅผ ์์ง ์์ ํ์ง ์์์ต๋๋ค. ๊พธ์คํ ์ฆ๊ฐํ๋ VMS๋ ํ์คํ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๊ฐ๋ฆฌํค๋ฉฐ RSS๋ ๋จ์ํ ๋ง์ ์์ malloc ์ผ ์ ์์ต๋๋ค (๊ฐ๋ฅํจ). ๋๋ถ๋ถ์ ์ด์ ์ฒด์ (๋ด๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ดํด ํ ๊ฒฝ์ฐ)๋ RSS๋ฅผ ์ด์ฌํ ํ์ํ์ง ์์ผ๋ฏ๋ก ๋ค๋ฅธ ์์ฉ ํ๋ก๊ทธ๋จ ํ์ด์ง์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ณ ์ด๋ฅผ ํ ๋น ํ ๋ค๋ฅธ ์์น๊ฐ ์์ ๋๊น์ง RSS๋ ์ถ์๋์ง ์์ต๋๋ค (๊ฐ๋ฅํ๋๋ผ๋). ์ฆ, ์ ์ ์ํ์ ๋๋ฌํ์ง ์๊ณ ์ง์์ ์ผ๋ก ์ฆ๊ฐํ๋ ๊ฒฝ์ฐ ์์ฒญ / urllib3์ธ์ง ์๋๋ฉด ์ธํฐํ๋ฆฌํฐ์ธ์ง ํ์ ํ ์ ์์ต๋๋ค.
๋๋ ์ด๊ฒ์ด ์ฐ๋ฆฌ์ ๋ฌธ์ ๊ฐ ์๋๋ผ๊ณ ์๊ฐํ๊ธฐ ์์ํ๊ธฐ ๋๋ฌธ์ urllib2 / httplib๋ฅผ ์ง์ ์ฌ์ฉํ ๋ ์ด๋ค ์ผ์ด ๋ฐ์ํ๋์ง ๋ณผ ๊ฒ์
๋๋ค. ๋ด๊ฐ ์ ์์๋ ํ, Session#close
๋ชจ๋ ์์ผ์ ์ฌ๋ฐ๋ฅด๊ฒ ๋ซ๊ณ GC๊ฐ ๋ ์ ์๋๋ก ํด๋น ์์ผ์ ๋ํ ์ฐธ์กฐ๋ฅผ ์ ๊ฑฐํฉ๋๋ค. ๋ํ ์์ผ์ ์ฐ๊ฒฐ ํ๋ก ๊ต์ฒดํด์ผํ๋ ๊ฒฝ์ฐ์๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค. SSLSocket์กฐ์ฐจ๋ ๊ฐ๋น์ง ์์ง์ ์ ๋๋ก ์ฒ๋ฆฌํ๋ ๊ฒ ๊ฐ์ต๋๋ค.
๋ฐ๋ผ์ urllib2๋ 13.3MiB ์ฃผ๋ณ์์ ์ผ๊ด๋๊ฒ ํํํ ๊ฒ์ฒ๋ผ ๋ณด์ ๋๋ค. ์ฐจ์ด์ ์ ์ ์ ํ URLError์ ํจ๊ป ์ง์์ ์ผ๋ก ์ถฉ๋ํ๊ธฐ ๋๋ฌธ์ try / except๋ก ๋ํํด์ผํ๋ค๋ ๊ฒ์ ๋๋ค. ๊ทธ๋์ ์๋ง๋ ์ ์ ํ์ ์ค์ ๋ก ์๋ฌด๊ฒ๋ํ์ง ์์ ๊ฒ์ ๋๋ค.
@ sigmavirus24 ๋น์ ์ ๊ทธ๊ฒ์ ๋ถ์ํ๊ณ ์์ต๋๋ค! :)
ํ ... Python์ ์์ฒด์ ์ผ๋ก ๋ค์ ์ฌ์ฉํ ์ ์๋๋ก ๋ฉ๋ชจ๋ฆฌ ๋ง ํด์ ํ๊ณ ํ๋ก์ธ์ค๊ฐ ์ข ๋ฃ ๋ ๋๊น์ง ์์คํ ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ค์ ๊ฐ์ ธ ์ค์ง ์์ต๋๋ค. ๋ฐ๋ผ์ 13.3MiB์์ ๋ณด๋ ํ๋ซ ๋ผ์ธ์ urllib3๊ณผ ๋ฌ๋ฆฌ urllib2์ ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ์์์ ๋ํ๋ด๋ ๊ฒ ๊ฐ์ต๋๋ค.
๋ฌธ์ ๊ฐ urllib3์ ๊ฒฉ๋ฆฌ ๋ ์ ์๋์ง ํ์ธํ๋ ๊ฒ์ด ์ข์ต๋๋ค. urllib2๋ก ํ ์คํธํ๋ ๋ฐ ์ฌ์ฉ์ค์ธ ์คํฌ๋ฆฝํธ๋ฅผ ๊ณต์ ํ ์ ์์ต๋๊น?
๊ทธ๋์ ๋๋ ์ด๊ฒ์ด HTTPConnection
๊ฐ์ฒด์ ๊ด๋ จ์ด ์๋์ง ๊ถ๊ธํดํ๊ธฐ ์์ํ์ต๋๋ค. ๋ง์ฝ ๋น์ ์ด
import sys
import requests
s = requests.Session()
r = s.get('https://httpbin.org/get')
print('Number of response refs: ', sys.getrefcount(r) - 1)
print('Number of session refs: ', sys.getrefcount(s) - 1)
print('Number of raw refs: ', sys.getrefcount(r.raw) - 1)
print('Number of original rsponse refs: ', sys.getrefcount(r.raw._original_response) - 1)
์ฒ์ ์ธ ๊ฐ๋ 1, ๋ง์ง๋ง 3 ๊ฐ๋ฅผ ์ธ์ํด์ผํฉ๋๋ค. [1] ์ด๋ฏธ HTTPConnection์ _HTTPConnection__response
์ ๋ํ ์ฐธ์กฐ ์ธ _original_response
. ๊ทธ๋์ ์ ๋ ๊ทธ ์ซ์๊ฐ 3์ด ๋ ๊ฒ์ผ๋ก ์์ํ์ต๋๋ค. ์ ๊ฐ ์์๋ผ ์์๋ ๊ฒ์ ์ธ ๋ฒ์งธ ์ฌ๋ณธ์ ๋ํ ์ฐธ์กฐ๋ฅผ ๋ณด์ ํ๊ณ ์๋ ๊ฒ์
๋๋ค.
์ถ๊ฐ ์ํฐํ ์ธ๋จผํธ๋ฅผ ์ํด ๋ค์์ ์ถ๊ฐํ์ญ์์ค.
import gc
gc.set_debug(gc.DEBUG_STATS | gc.DEBUG_UNCOLLECTABLE)
์คํฌ๋ฆฝํธ์ ์์ ๋ถ๋ถ์. ํฅ๋ฏธ๋ก์ด ์์ฒญ์ ํธ์ถ ํ ํ ๋๋ฌ ํ ์์๋ ๊ฐ์ฒด๊ฐ 2 ๊ฐ ์์ง๋ง ์์ง ํ ์์๋ ๊ฒ์ ์์ต๋๋ค. @mhjohnson์ด ์ ๊ณต ํ ์คํฌ๋ฆฝํธ์ ์ด๊ฒ์ ์ถ๊ฐํ๊ณ ๋๋ฌ ํ ์์๋ ํ์ ๋ํ ์ถ๋ ฅ์ ํํฐ๋งํ๋ฉด ๋๋ฌ ํ ์์๋ ๊ฐ์ฒด๊ฐ 300 ๊ฐ๊ฐ ํจ์ฌ ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค. ๋๋ ์์ง ๋๋ฌ ํ ์์๋ ๊ฐ์ฒด์ ์ค์์ฑ์ ์์ง ๋ชปํฉ๋๋ค. ํญ์ ๊ทธ๋ ๋ฏ์ด ๋ชจ๋ ๊ฒ์ํ๊ฒ ์ต๋๋ค.
ํ
์คํธ urllib3์ @mhjohnson, ๊ทธ๋ฅ์ ์ ํ๋ฅผ ๋์ฒด requests.get
์ urllib2.urlopen
(๋ํ ๋ด๊ฐ ์๋ง ์ผ์ ํ์ด์ผ r.read()
ํ์ง๋ง ๋ํ์ง ์์๋ค).
๊ทธ๋์ @mhjohnson ์ ์ด์ ์ ์์ objgraph
๋ฅผ ์ฌ์ฉํ์ฌ ๋ค๋ฅธ ์ฐธ์กฐ๊ฐ ์ด๋์ ์๋์ง ์์ ๋์ง๋ง objgraph๊ฐ ์ฐพ์ ์์๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋๋ ์ถ๊ฐํ๋ค :
objgraph.show_backrefs([r.raw._original_response], filename='requests.png')
์์ ์คํฌ๋ฆฝํธ์์ 2 ๊ฐ์ ์ฃผ์์ ๋ฌ๊ณ ๋ค์์ ์ป์์ต๋๋ค.
2 ๊ฐ์ ์ฐธ์กฐ๊ฐ ์์์ ๋ณด์ฌ์ค๋๋ค. ์ ๋ขฐํ ์์๋ sys.getrefcount
์๋ ๋ฐฉ์์ ๋ฌธ์ ๊ฐ ์๋์ง ๊ถ๊ธํฉ๋๋ค.
๊ทธ๋์ ๊ทธ๊ฒ์ ๋ถ์ ์ฒญ์ด์
๋๋ค. urllib3.response.HTTPResponse
์๋ _original_response
๋ฐ _fp
์์ต๋๋ค. _HTTPConection__response
์ ๊ฒฐํฉํ๋ฉด ์ธ ๊ฐ์ ์ฌํ์ด ์ ๊ณต๋ฉ๋๋ค.
๊ทธ๋์, urllib3.response.HTTPResponse
์ด _pool
๋์ ์ํด ์ฐธ์กฐ๋๋ ์์ฑ PoolManager
. ๋ง์ฐฌ๊ฐ์ง๋ก ์์ฒญ์ ๋ง๋๋ ๋ฐ ์ฌ์ฉ ๋ HTTPAdapter
์๋ Response
์์ฒญ ๋ฐํ์ ๋ํ ์ฐธ์กฐ๊ฐ ์์ต๋๋ค. ๋ค๋ฅธ ์ฌ๋์ด ์ฌ๊ธฐ์์ ๋ฌด์ธ๊ฐ๋ฅผ ์๋ณ ํ ์ ์์ต๋๋ค.
์์ฑํ๋ ์ฝ๋ : https://gist.github.com/sigmavirus24/bc0e1fdc5f248ba1201d
์๋
ํ์ธ์.
๊ทธ๋, ๋ง์ง๋ง ๊ทธ๋ํฝ์ผ๋ก ์ข ์์ด ๋ฒ๋ ธ์ด. ์๋ง๋ ๋ด๊ฐ ์ฝ๋๋ฒ ์ด์ค๋ฅผ ์ ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์ด๊ฑฐ๋ ๋ฉ๋ชจ๋ฆฌ ๋์ ๋๋ฒ๊น
์ ๋ฅ์ํ์ง ์๊ธฐ ๋๋ฌธ์ผ ๊ฒ์ด๋ค.
์ด ๊ทธ๋ํฝ ์คํฌ๋ฆฐ ์ท์์ ๋นจ๊ฐ์ ํ์ดํ๋ก ๊ฐ๋ฆฌํค๋ ๋ฌผ์ฒด๊ฐ ๋ฌด์์ธ์ง ์์ญ๋๊น?
http://cl.ly/image/3l3g410p3r1C
์ฒ์ฒํ ์ฆ๊ฐํ๋ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ๋ณด์ฌ์ฃผ๋ ์ฝ๋๋ฅผ ์ป์ ์์์์ต๋๋ค.
urllib3 / requests๋ฅผ urllib.request.urlopen์ผ๋ก ๋์ฒดํ์ฌ python3์์.
์์ ๋ ์ฝ๋ : https://gist.github.com/kevinburke/f99053641fab0e2259f0
์ผ๋น ๋ฒํฌ
์ ํ : 925.271.7005 | twentymilliseconds.com
2014 ๋
11 ์ 3 ์ผ ์์์ผ ์คํ 9:28, Matthew Johnson [email protected]
์ผ๋ค :
@ sigmavirus24 https://github.com/sigmavirus24
๊ทธ๋, ๋ง์ง๋ง ๊ทธ๋ํฝ์ผ๋ก ์ข ์์ด ๋ฒ๋ ธ์ด. ์๋ง ๋ด๊ฐํ์ง ์๊ธฐ ๋๋ฌธ์
์ฝ๋ ๊ธฐ๋ฐ์ ์ ์๊ณ ์๊ณ , ๋ฉ๋ชจ๋ฆฌ ๋๋ฒ๊น ์ ๋ฅ์ํ์ง๋ ์์ต๋๋ค.
๋์ถ.๋ด๊ฐ ๋นจ๊ฐ์ ํ์ดํ๋ก ๊ฐ๋ฆฌํค๋ ๋ฌผ์ฒด๊ฐ ๋ฌด์์ธ์ง ์์ญ๋๊น?
์ด ๊ทธ๋ํฝ ์คํฌ๋ฆฐ ์ท์์?
http://cl.ly/image/3l3g410p3r1Cโ
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ฑฐ๋ GitHub์์ ํ์ธํ์ธ์.
https://github.com/kennethreitz/requests/issues/1685#issuecomment -61595362
.
๋ด๊ฐ ๋ฐํํ๋ ์น ์ฌ์ดํธ์ ๋ํ ์์ฒญ์ ๋งํ ์์๋ ํ
์ฐ๊ฒฐ : ํค๋ ๋ซ๊ธฐ (์ : https://api.twilio.com/2010-04-01.json)
๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ํฌ๊ฒ ๋๋ฆฌ์ง ์์ต๋๋ค. ์ฃผ์ ์ฌํญ์
์ฌ๋ฌ ๊ฐ์ง ์์๊ฐ ์์ผ๋ฉฐ ์์ผ์ด๋ผ๊ณ ๊ฐ์ ํฉ๋๋ค.
๊ด๋ จ ๋ฌธ์ .
์ผ๋น ๋ฒํฌ
์ ํ : 925.271.7005 | twentymilliseconds.com
2014 ๋ 11 ์ 3 ์ผ ์์์ผ ์คํ 9์ 43 ๋ถ์ Kevin Burke [email protected] ์ ๋ค์๊ณผ ๊ฐ์ด ์ผ์ต๋๋ค.
์ฒ์ฒํ ์ฆ๊ฐํ๋ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ๋ณด์ฌ์ฃผ๋ ์ฝ๋๋ฅผ ์ป์ ์์์์ต๋๋ค.
urllib3 / requests๋ฅผ urllib.request.urlopen์ผ๋ก ๋์ฒดํ์ฌ python3์์.์ฌ๊ธฐ์ ์์ ๋ ์ฝ๋ :
https://gist.github.com/kevinburke/f99053641fab0e2259f0์ผ๋น ๋ฒํฌ
์ ํ : 925.271.7005 | twentymilliseconds.com2014 ๋ 11 ์ 3 ์ผ ์์์ผ ์คํ 9:28, Matthew Johnson [email protected]
์ผ๋ค :@ sigmavirus24 https://github.com/sigmavirus24
๊ทธ๋, ๋ง์ง๋ง ๊ทธ๋ํฝ์ผ๋ก ์ข ์์ด ๋ฒ๋ ธ์ด. ์๋ง ๋ด๊ฐ
์ฝ๋๋ฒ ์ด์ค๋ฅผ ์ ๋ชจ๋ฅด๊ฑฐ๋ ๋๋ฒ๊น ์ ๋ฅ์ํ์ง ์์ต๋๋ค.
๋ฉ๋ชจ๋ฆฌ ๋์.๋ด๊ฐ ๋นจ๊ฐ์ ํ์ดํ๋ก ๊ฐ๋ฆฌํค๋ ๋ฌผ์ฒด๊ฐ ๋ฌด์์ธ์ง ์์ญ๋๊น?
์ด ๊ทธ๋ํฝ ์คํฌ๋ฆฐ ์ท์์?
http://cl.ly/image/3l3g410p3r1Cโ
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ฑฐ๋ GitHub์์ ํ์ธํ์ธ์.
https://github.com/kennethreitz/requests/issues/1685#issuecomment -61595362
.
@mhjohnson ์ type
์ ํ์ object
์ํ ๋ฉํ ์ ํ type
์ ๋ํ ์ฐธ์กฐ ์์ธ ๊ฒ ๊ฐ์ต๋๋ค. ์ฆ, object
๋๋ type
์ ๋ชจ๋ ์ฐธ์กฐ๋ผ๊ณ ์๊ฐํ์ง๋ง ํ์คํ์ง ์์ต๋๋ค. ์ด๋ ์ชฝ์ด๋ ์ ์ธํ๋ ค๊ณ ํ๋ฉด ๊ทธ๋ํ๋ 2 ๊ฐ์ ๋
ธ๋์ ๊ฐ์ ๋ชจ์์ด๋ฉ๋๋ค.
๋ํ ํ๋ก์ธ์ค๊ฐ ๋ณดํต ๋ฉฐ์น ๋์ ์คํ๋๋ ์น ํฌ๋กค๋ง ์์คํ ์์ ์์ฒญ์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์์ด ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฌธ์ ์ ๋ํด ๋งค์ฐ ์ผ๋ คํฉ๋๋ค. ์ด ๋ฌธ์ ์ ๋ํ ์ง์ ์ด ์์ต๋๊น?
@mhjohnson ๊ณผ ํจ๊ป ์ด๊ฒ์ ๋ํด ์๊ฐ์ ๋ณด๋ธ ํ, GC๊ฐ PyPy์์ ์์ผ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์๊ณผ ๊ด๋ จ๋ @kevinburke ์ด๋ก ์ ํ์ธํ ์ ์์ต๋๋ค.
3c0b94047c1ccfca4ac4f2fe32afef0ae314094e ์ปค๋ฐ์ ํฅ๋ฏธ๋ก์ด ๊ฒ์ ๋๋ค. ํนํ https://github.com/kennethreitz/requests/blob/master/requests/models.py#L736 ๋ผ์ธ
์ฝํ
์ธ ๋ฅผ ๋ฐํํ๊ธฐ ์ ์ self.raw.release_conn()
๋ฅผ ํธ์ถํ๋ฉด PyPy์์ ์ฌ์ฉ ๋ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํฌ๊ฒ ์ค์ด๋ค์์ง๋ง ์ฌ์ ํ ๊ฐ์ ์ ์ฌ์ง๊ฐ ์์ต๋๋ค.
๋ํ @ sigmavirus24์์๋ ์ธ๊ธํ๋ฏ์ด ์ธ์
๋ฐ ์๋ต ํด๋์ค์ ๊ด๋ จ๋ .close()
ํธ์ถ์ ๋ฌธ์ํํ๋ฉด ๋ ์ข์ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ๋ฉ์๋๊ฐ ์์ ์ ์ผ๋ก ํธ์ถ๋์ง ์๊ธฐ ๋๋ฌธ์ ์์ฒญ ์ฌ์ฉ์๋ ์ด๋ฌํ ๋ฉ์๋๋ฅผ ์๊ณ ์์ด์ผํฉ๋๋ค.
์ด ํ๋ก์ ํธ์ QA์ ๊ด๋ จ๋ ์ง๋ฌธ๊ณผ ์ ์์ด ์์ต๋๋ค. ํ ์คํธ์ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด CI๋ฅผ ์ฌ์ฉํ์ง ์๋ ์ด์ ๋ฅผ ๊ด๋ฆฌ์์๊ฒ ๋ฌผ์ด๋ด๋ ๋ ๊น์? CI๊ฐ ์์ผ๋ฉด ์ฑ๋ฅ / ๋ฉ๋ชจ๋ฆฌ ํ๊ท๋ฅผ ํ๋กํ์ผ ๋งํ๊ณ ์ถ์ ํ ์์๋ ๋ฒค์น ๋งํฌ ํ ์คํธ ์ผ์ด์ค๋ฅผ ์์ฑํ ์๋ ์์ต๋๋ค.
์ด๋ฌํ ์ ๊ทผ ๋ฐฉ์์ ์ข์ ์๋ pq ํ๋ก์ ํธ์์ ์ฐพ์ ์ ์์ต๋๋ค.
https://github.com/malthe/pq/blob/master/pq/tests.py#L287
์ด๊ฒ์ ๋ฐ์ด ๋ค๊ณ ๋์์ ์ฃผ๊ธฐ๋ก ๊ฒฐ์ ํ ๋ชจ๋ ์ฌ๋์๊ฒ ๊ฐ์ฌ๋๋ฆฝ๋๋ค!
์ฐ๋ฆฌ๋ ์ด๊ฒ์ ์ผ์ผํค๋ ๋ค๋ฅธ ์ด๋ก ์ ๊ณ์ ์กฐ์ฌ ํ ๊ฒ์
๋๋ค.
@stas ํ ๊ฐ์ง๋ฅผ ๋ค๋ฃจ๊ณ ์ถ์ต๋๋ค.
๋๋ถ๋ถ์ ๊ฒฝ์ฐ ๋ฉ์๋๊ฐ ์์ ์ ์ผ๋ก ํธ์ถ๋์ง ์๊ธฐ ๋๋ฌธ์ ์์ฒญ ์ฌ์ฉ์๋ ์ด๋ฌํ ๋ฉ์๋๋ฅผ ์๊ณ ์์ด์ผํฉ๋๋ค.
PyPy๋ฅผ ์ ์ ๋๋๊ณ , ์ด๋ฌํ ๋ฉ์๋๋ฅผ ๋ช ์ ์ ์ผ๋ก ํธ์ถ ํ ํ์๊ฐ _ ์๋ฉ๋๋ค _. CPython์์ ์์ผ ๊ฐ์ฒด์ ๋๋ฌ ํ ์ ์๊ฒ๋๋ฉด ์๋ gc'd๋ฅผ ๋ฐ๊ฒ๋๋ฉฐ, ์ฌ๊ธฐ์๋ ํ์ผ ํธ๋ค ๋ซ๊ธฐ๊ฐ ํฌํจ๋ฉ๋๋ค. ์ด๊ฒ์ ์ด๋ฌํ ๋ฉ์๋๋ฅผ ๋ฌธ์ํํ์ง ์๋๋ค๋ ์ฃผ์ฅ์ ์๋์ง๋ง ์ง๋์น๊ฒ ์ง์คํ์ง ๋ง๋ผ๋ ๊ฒฝ๊ณ ์ ๋๋ค.
์ฐ๋ฆฌ๋ CI๋ฅผ ์ฌ์ฉํ๋๋ก๋์ด ์์ง๋ง, ํ์ฌ ์ํ๊ฐ ์ข์ง ์์ ๊ฒ ๊ฐ์ผ๋ฉฐ @kennethreitz ๋ง์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์์๋ ์์น์ ์์ต๋๋ค. ๊ทธ๋ ์๊ฐ์ด์์ ๋ ๊ทธ๊ฒ์ ์ป์ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ ๋ฒค์น ๋งํฌ ํ ์คํธ๋ ๋งค์ฐ ์๋๋ฝ์ง ์์ ๋ฐฉ์์ผ๋ก ์ ๋๋ก ์๋ํ๊ธฐ๊ฐ ๋งค์ฐ ์ด๋ ต์ต๋๋ค.
PyPy๋ฅผ ์ ์ ๋๋๋ฉด ์ด๋ฌํ ๋ฉ์๋๋ฅผ ๋ช ์ ์ ์ผ๋ก ํธ์ถ ํ ํ์๊ฐ ์์ต๋๋ค. CPython์์ ์์ผ ๊ฐ์ฒด์ ๋๋ฌ ํ ์ ์๊ฒ๋๋ฉด ์๋ gc'd๋ฅผ ๋ฐ๊ฒ๋๋ฉฐ, ์ฌ๊ธฐ์๋ ํ์ผ ํธ๋ค ๋ซ๊ธฐ๊ฐ ํฌํจ๋ฉ๋๋ค. ์ด๊ฒ์ ์ด๋ฌํ ๋ฉ์๋๋ฅผ ๋ฌธ์ํํ์ง ์๋๋ค๋ ์ฃผ์ฅ์ ์๋์ง๋ง ์ง๋์น๊ฒ ์ง์คํ์ง ๋ง๋ผ๋ ๊ฒฝ๊ณ ์ ๋๋ค.
์ฌ๊ธฐ์ ํ์ด์ฌ์ ๋ํด ๋
ผ์ํ๋ ๋ถ๋ถ์ ์ ์ธํ๊ณ ๋ ์ฌ๋ฌ๋ถ์ด ๋งํ๋ ๊ฒ์ ๋์ํฉ๋๋ค. ๋๋ ๋
ผ์์ ์์ํ๊ณ ์ถ์ง ์์ง๋ง _The Zen of Python_์ ์ฝ๊ณ , ํ์ด์ฌ์ ์ธ ๋ฐฉ๋ฒ์ _Explicit๊ฐ implicit_ ์ ๊ทผ ๋ฐฉ์๋ณด๋ค ๋ซ์ต๋๋ค. ๋๋ ๋ํ์ด ํ๋ก์ ํธ ์ฒ ํ์ ์ต์ํ์ง ์์ผ๋ฏ๋ก requests
์ ์ฉ๋์ง ์์ผ๋ฉด ๋ด ์๊ฐ์ ๋ฌด์ํ์ญ์์ค.
๊ธฐํ๊ฐ์์ ๋๋ง๋ค CI ๋๋ ๋ฒค์น ๋งํฌ ํ ์คํธ๋ฅผ ๋์ ๋๋ฆฌ๊ฒ ์ต๋๋ค! ํ์ฌ ์ํฉ์ ์ค๋ช ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
๊ทธ๋์ ๊ธฐ๋ฅ API๋ฅผ ์ฌ์ฉํ ๋ ๋ฌธ์ ์ ์์ธ์ ์ฐพ์ ๊ฒ ๊ฐ์ต๋๋ค. ๋ง์ฝ ๋น์ ์ด
import requests
r = requests.get('https://httpbin.org/get')
print(r.raw._pool.pool.queue[-1].sock)
์์ผ์ด ์์ง ์ด๋ ค์๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋ด๊ฐ _appears_๋ผ๊ณ ๋งํ๋ ์ด์ ๋ ์ฌ์ ํ _sock
์์ฑ์ด ์๊ธฐ ๋๋ฌธ์
๋๋ค.
r.raw._pool.queue[-1].close()
print(repr(r.raw._pool.queue[-1].sock))
None
์ธ์ ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ urllib3
๋ ๋ชจ๋ HTTPResponse
์ ์ฐ๊ฒฐ ํ์ ๊ฐ๋ฆฌํค๋ ์์ฑ์ ํฌํจํฉ๋๋ค. ์ฐ๊ฒฐ ํ์๋ ๋ซํ์ง ์์ ์์ผ์ด์๋ ํ์ Connection์ด ์์ต๋๋ค. ๊ธฐ๋ฅ์ API์ ๋ฌธ์ ๋ requests/api.py
๊ฐ์ดํ๋ฉด ํด๊ฒฐ๋ฉ๋๋ค.
def request(...):
"""..."""
s = Session()
response = s.request(...)
s.close()
return s
๊ทธ๋ฌ๋ฉด r.raw._pool
์ (๋) ์ฌ์ ํ ์ฐ๊ฒฐ ํ์ด์ง๋ง r.raw._pool.pool
์ (๋) None
์
๋๋ค.
๊น๋ค๋ก์ด ๋ถ๋ถ์ ์ฌ๋๋ค์ด ์ธ์
์ ์ฌ์ฉํ ๋ ์ผ์ด๋๋ ์ผ์ด๋ฉ๋๋ค. ๋ชจ๋ ์์ฒญ ํ์ ์ธ์
์ close
๊ฐ๋ ๊ฒ์ ๋ง๋ ์๋๋ฉฐ ์ธ์
์ ๋ชฉ์ ์ ์๋ฐฐ๋ฉ๋๋ค. ์ค์ ๋ก ์ธ์
(์ค๋ ๋ ์์)์ ์ฌ์ฉํ๊ณ ์ธ์
์ ์ฌ์ฉํ์ฌ ๋์ผํ ๋๋ฉ์ธ (๋ฐ ๋์ผํ ์คํค๋ง (์ : https
))์ 100 ๊ฐ์ ์์ฒญ์ ์ํํ๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ํ์ธํ๊ธฐ๊ฐ ํจ์ฌ ๋ ์ด๋ ต์ต๋๋ค. ์ ์์ผ์ด ์์ฑ ๋ ๋๊น์ง ์ฝ 30 ์ด ๋์ ๊ธฐ๋ค๋ฆฌ์ญ์์ค. ๋ฌธ์ ๋ ์ฐ๋ฆฌ๊ฐ ์ด๋ฏธ ๋ณด์ ๋ฏ์ด r.raw._pool
๋ ๋งค์ฐ ๊ฐ๋ณ์ ์ธ ๊ฐ์ฒด๋ผ๋ ๊ฒ์
๋๋ค. ์์ฒญ์์ ํ ๊ด๋ฆฌ์๊ฐ ๊ด๋ฆฌํ๋ ์ฐ๊ฒฐ ํ์ ๋ํ ์ฐธ์กฐ์
๋๋ค. ๋ฐ๋ผ์ ์์ผ์ด ๊ต์ฒด๋๋ฉด ์ฌ์ ํ ๋๋ฌ ํ ์์๋ (๋ฒ์ ๋ด) ๋ชจ๋ ์๋ต์ ์ฐธ์กฐ๋ก ๊ต์ฒด๋ฉ๋๋ค. ๋ ๋ง์ ์์
์ ์ํํด์ผํ๋ ๊ฒ์ ์ฐ๊ฒฐ ํ์ ๋ซ์ ํ์๋ ์์ผ์ ๋ํ ์ฐธ์กฐ๊ฐ ์ฌ์ ํ ์ ์ง๋๋์ง ํ์ธํ๋ ๊ฒ์
๋๋ค. ์ฐธ์กฐ๋ฅผ ๋ถ์ก๊ณ ์๋ ๊ฒ์ ์ฐพ์ ์ ์๋ค๋ฉด _real_ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐ๊ฒฌ ํ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
๊ทธ๋์ ๋ด๊ฐ ๊ฐ์ง ๊ฒ์ ํ๋ ๊ฐ์ ์์ด๋์ด๋ ์ค์ ๋ก ์ฐธ์กฐ ์์๋ผ objgraph ์ฌ์ฉํ๋ ๊ฒ์ด ์์ต๋๋ค SSLSocket
๋ฅผ ํธ์ถ ํ ํ requests.get
๋๋์ด์์ด :
ํฅ๋ฏธ๋ก์ด ์ ์ SSLSocket
๋ํ ์ฐธ์กฐ๊ฐ 7 ๊ฐ๊ฐ ๋ถ๋ช
ํ์ง๋ง objgraph๊ฐ ์ฐพ์ ์์๋ ์ญ ์ฐธ์กฐ๋ 2 ๊ฐ๋ฟ์ด๋ผ๋ ๊ฒ์
๋๋ค. ์ฐธ์กฐ ์ค ํ๋๋ objgraph์ ์ ๋ฌ ๋ ๊ฒ์ด๊ณ ๋ค๋ฅธ ํ๋๋ ์ด๊ฒ์ ์์ฑํ๋ ์คํฌ๋ฆฝํธ์์ ๋ง๋ ๋ฐ์ธ๋ฉ์ด๋ผ๊ณ ์๊ฐํ์ง๋ง ์ฌ์ ํ ์ฐธ์กฐ๊ฐ ์ด๋์์ ์ค๋์ง ํ์คํ์ง ์์ ์ฐธ์กฐ์ ๋ํด 3 ๊ฐ ๋๋ 4 ๊ฐ๋ ์ค๋ช
๋์ง ์์ต๋๋ค.
์ด๊ฒ์ ์์ฑํ๋ ์คํฌ๋ฆฝํธ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
import objgraph
import requests
r = requests.get('https://httpbin.org/get')
s = r.raw._pool.pool.queue[-1].sock
objgraph.show_backrefs(s, filename='socket.png', max_depth=15, refcounts=True)
์ฌ์ฉ
import objgraph
import requests
r = requests.get('https://httpbin.org/get')
s = r.raw._pool.pool.queue[-1].sock
objgraph.show_backrefs(s, filename='socket-before.png', max_depth=15,
refcounts=True)
r.raw._pool.close()
objgraph.show_backrefs(s, filename='socket-after.png', max_depth=15,
refcounts=True)
socket-after.png
๋ ๋ค์์ ๋ณด์ฌ์ค๋๋ค.
๋ฐ๋ผ์ SSL ์์ผ์ ๋ํ ํ๋์ ์ฐธ์กฐ๋ฅผ ์ ๊ฑฐํฉ๋๋ค. ์ฆ, s._sock
๋ณด๋ฉด ๊ธฐ๋ณธ socket.socket
๊ฐ ๋ซํ๋๋ค.
์ฅ๊ธฐ ์คํ ๋ฒค์น ๋งํฌ๋ฅผ ์คํ ํ ํ ๋ค์๊ณผ ๊ฐ์ ์ฌ์ค์ ๋ฐ๊ฒฌํ์ต๋๋ค.
close()
ํธ์ถํ๋ฉด ๋์์ด๋ฉ๋๋ค!Session
์ (๋ฅผ) ์ฌ์ฉํ๊ณ ์๋ฃ ํ ์ ๋๋ก ๋ซ์์ผํฉ๋๋ค. # 2326์ ๋ณํฉํ์ญ์์คgc.collect()
๋ช
์ ์ ์ผ๋ก ํธ์ถํด์ผํฉ๋๋ค!TL; DR; requests
๊ด์ฐฎ์ ๋ณด์
๋๋ค. ์๋์์ด ์ค ๋ํซ์ ์คํํ๋ ๋ช ๊ฐ์ง ์ฐจํธ๊ฐ ์์ต๋๋ค.
import requests
from memory_profiler import profile
<strong i="15">@profile</strong>
def get(session, i):
return session.get('http://stas.nerd.ro/?{0}'.format(i))
<strong i="16">@profile</strong>
def multi_get(session, count):
for x in xrange(count):
resp = get(session, count+1)
print resp, len(resp.content), x
resp.close()
<strong i="17">@profile</strong>
def run():
session = requests.Session()
print 'Starting...'
multi_get(session, 3000)
print("Finished first round...")
session.close()
print 'Done.'
if __name__ == '__main__':
run()
CPython :
Line # Mem usage Increment Line Contents
================================================
15 9.1 MiB 0.0 MiB <strong i="23">@profile</strong>
16 def run():
17 9.1 MiB 0.0 MiB session = requests.Session()
18 9.1 MiB 0.0 MiB print 'Starting...'
19 9.7 MiB 0.6 MiB multi_get(session, 3000)
20 9.7 MiB 0.0 MiB print("Finished first round...")
21 9.7 MiB 0.0 MiB session.close()
22 9.7 MiB 0.0 MiB print 'Done.'
JIT๊ฐ์๋ PyPy :
Line # Mem usage Increment Line Contents
================================================
15 15.0 MiB 0.0 MiB <strong i="29">@profile</strong>
16 def run():
17 15.4 MiB 0.5 MiB session = requests.Session()
18 15.5 MiB 0.0 MiB print 'Starting...'
19 31.0 MiB 15.5 MiB multi_get(session, 3000)
20 31.0 MiB 0.0 MiB print("Finished first round...")
21 31.0 MiB 0.0 MiB session.close()
22 31.0 MiB 0.0 MiB print 'Done.'
JIT๋ฅผ ์ฌ์ฉํ PyPy :
Line # Mem usage Increment Line Contents
================================================
15 22.0 MiB 0.0 MiB <strong i="35">@profile</strong>
16 def run():
17 22.5 MiB 0.5 MiB session = requests.Session()
18 22.5 MiB 0.0 MiB print 'Starting...'
19 219.0 MiB 196.5 MiB multi_get(session, 3000)
20 219.0 MiB 0.0 MiB print("Finished first round...")
21 219.0 MiB 0.0 MiB session.close()
22 219.0 MiB 0.0 MiB print 'Done.'
์ฒ์์ ์ฐ๋ฆฌ ๋ชจ๋๊ฐ ํผ๋์ค๋ฌ์ํ๋ ์ด์ ์ค ํ๋๋ ๋ฒค์น ๋งํฌ๋ฅผ ์คํํ๋ ค๋ฉด GC๊ฐ ํ ๊ตฌํ์์ ๋ค๋ฅธ ๊ตฌํ์ผ๋ก ์๋ํ๋ ๋ฐฉ์์ ์ ์ธํ๊ธฐ ์ํด ๋ ํฐ ์ธํธ๊ฐ ํ์ํ๊ธฐ ๋๋ฌธ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
๋ํ ์ค๋ ๋ ํ๊ฒฝ์์ ์์ฒญ์ ์คํํ๋ ค๋ฉด ์ค๋ ๋๊ฐ ์๋ํ๋ ๋ฐฉ์์ผ๋ก ์ธํด ๋ ๋ง์ ํธ์ถ ์ธํธ๊ฐ ํ์ํฉ๋๋ค (์ฌ๋ฌ ์ค๋ ๋ ํ์ ์คํ ํ ํ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ํฐ ๋ณํ๊ฐ ์์).
JIT๋ฅผ ์ฌ์ฉํ๋ PyPy์ ๊ด๋ จํ์ฌ ๋์ผํ ์์ ํธ์ถ์ ๋ํด gc.collect()
๋ฅผ ํธ์ถํ๋ฉด ๋ฉ๋ชจ๋ฆฌ๊ฐ ~ 30 % ์ ์ฝ๋ฉ๋๋ค. ์ด๊ฒ์ด ๋ชจ๋ ์ฌ๋๋ค์ด VM์ ์กฐ์ ํ๊ณ JIT์ ๋ํ ์ฝ๋๋ฅผ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ ์ฃผ์ ์ด๊ธฐ ๋๋ฌธ์ JIT ๊ฒฐ๊ณผ๋์ด ํ ๋ก ์์ ์ ์ธ๋์ด์ผํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ข์, ๊ทธ๋์ ๋ฌธ์ ๋ ์ฐ๋ฆฌ๊ฐ PyPy JIT์ ์ํธ ์์ฉํ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์์๋ ๊ฒ ๊ฐ์ต๋๋ค. PyPy ์ ๋ฌธ๊ฐ ์ธ @alex?๋ฅผ ์ํํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋๋ ์ ๋ง๋ก ์ด์ ๊ฐ์ ์ผ์ ์ผ์ผํฌ ์์๋ ์์ฒญ (๋ฐ ํ์ฌ)์ด ๋ฌด์์ํ๊ณ ์๋์ง ์์ํ ์ ์์ต๋๋ค. ํ๊ฒฝ์์ PYPYLOG=jit-summary:-
๋ก ํ
์คํธ๋ฅผ ์คํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ถ์ฌ ๋ฃ์ ์ ์์ต๋๊น (ํ๋ก์ธ์ค๊ฐ ๋๋๋ฉด ์ผ๋ถ ๋ด์ฉ์ด ์ธ์๋ฉ๋๋ค)
๋์์ด ๋์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค:
Line # Mem usage Increment Line Contents
================================================
15 23.7 MiB 0.0 MiB <strong i="6">@profile</strong>
16 def run():
17 24.1 MiB 0.4 MiB session = requests.Session()
18 24.1 MiB 0.0 MiB print 'Starting...'
19 215.1 MiB 191.0 MiB multi_get(session, 3000)
20 215.1 MiB 0.0 MiB print("Finished first round...")
21 215.1 MiB 0.0 MiB session.close()
22 215.1 MiB 0.0 MiB print 'Done.'
[2cbb7c1bbbb8] {jit-summary
Tracing: 41 0.290082
Backend: 30 0.029096
TOTAL: 1612.933400
ops: 79116
recorded ops: 23091
calls: 2567
guards: 7081
opt ops: 5530
opt guards: 1400
forcings: 198
abort: trace too long: 2
abort: compiling: 0
abort: vable escape: 9
abort: bad loop: 0
abort: force quasi-immut: 0
nvirtuals: 9318
nvholes: 1113
nvreused: 6666
Total # of loops: 23
Total # of bridges: 8
Freed # of loops: 0
Freed # of bridges: 0
[2cbb7c242e8b] jit-summary}
https://launchpad.net/~pypy/+archive/ubuntu/ppa์ ์ต์ PyPy๋ฅผ ์ฌ์ฉํ์ฌ ์ ๋ขฐํ ์์๋ 32 ๋นํธ๋ฅผ ์ฌ์ฉํ๊ณ
31 ๊ฐ์ ์ปดํ์ผ ๋ ๊ฒฝ๋ก๋ ์ฌ์ฉ์ค์ธ 200MB ์ด์์ RAM์ ์ค๋ช ํ์ง ์์ต๋๋ค.
์คํํ ํ๋ก๊ทธ๋จ์ ๋ฌด์ธ๊ฐ๋ฅผ ๋ฃ์ ์ ์์ต๋๊น?
gc.dump_rpy_heap('filename.txt')
๋งค์ฐ ๋์ ๋ฉ๋ชจ๋ฆฌ์์์ ๋
์ฉ๋ฒ? (ํ ๋ฒ๋ง ์คํํ๋ฉด๋ฉ๋๋ค. ์ด๋ ๊ฒํ๋ฉด ๋ชจ๋
GC๊ฐ ์๊ณ ์๋ ๋ฉ๋ชจ๋ฆฌ).
๊ทธ๋ฐ ๋ค์ PyPy ์์ค ํธ๋ฆฌ๋ฅผ ํ์ธํ๊ณ ./pypy/tool/gcdump.py
filename.txt
์คํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฌ์ค๋๋ค.
๊ฐ์ฌ!
2014 ๋
11 ์ 8 ์ผ ํ ์์ผ ์คํ 3:20:52 Stas Suศcov [email protected]
์ผ๋ค :
๋์์ด ๋์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค:
๋ผ์ธ ๋ฒํธ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ฆ๊ฐ ๋ผ์ธ ์ฝํ ์ธ
15 23.7 MiB 0.0 MiB <strong i="20">@profile</strong> 16 def run(): 17 24.1 MiB 0.4 MiB session = requests.Session() 18 24.1 MiB 0.0 MiB print 'Starting...' 19 215.1 MiB 191.0 MiB multi_get(session, 3000) 20 215.1 MiB 0.0 MiB print("Finished first round...") 21 215.1 MiB 0.0 MiB session.close() 22 215.1 MiB 0.0 MiB print 'Done.'
[2cbb7c1bbbb8] {jit-summary
์ถ์ : 41 0.290082
๋ฐฑ์๋ : 30 0.029096
ํฉ๊ณ : 1612.933400
์์ : 79116
๊ธฐ๋ก ๋ ์์ : 23091
์ ํ : 2567
๊ฒฝ๋น์ : 7081
์ ํ ์์ : 5530
์ตํธ ๊ฐ๋ : 1400
๊ฐ์ ๋ ฅ : 198
์ค๋จ : ์ถ์ ์ด ๋๋ฌด ๊น : 2
์ค๋จ : ์ปดํ์ผ : 0
abort : vable escape : 9
abort : ์๋ชป๋ ๋ฃจํ : 0
abort : ๊ฐ์ ์ ์ฌ ๋ถ๋ณ : 0
nvirtuals : 9318
nvholes : 1113
nvreused : 6666
์ด ๋ฃจํ ์ : 23
์ด ๊ต๋ ์ : 8
ํด์ ๋ ๋ฃจํ ์ : 0
ํด์ ๋ ๋ธ๋ฆฌ์ง ์ : 0
[2cbb7c242e8b] jit-summary}๋๋ ์ต์ PyPy๋ฅผ ์ฌ์ฉํ์ฌ ์ ๋ขฐํ ์์๋ 32 ๋นํธ๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
https://launchpad.net/~pypy/+archive/ubuntu/ppa
https://launchpad.net/%7Epypy/+archive/ubuntu/ppaโ
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ฑฐ๋ GitHub์์ ํ์ธํ์ธ์.
https://github.com/kennethreitz/requests/issues/1685#issuecomment -62269627
.
๋ก๊ทธ:
Line # Mem usage Increment Line Contents
================================================
16 22.0 MiB 0.0 MiB <strong i="6">@profile</strong>
17 def run():
18 22.5 MiB 0.5 MiB session = requests.Session()
19 22.5 MiB 0.0 MiB print 'Starting...'
20 217.2 MiB 194.7 MiB multi_get(session, 3000)
21 217.2 MiB 0.0 MiB print("Finished first round...")
22 217.2 MiB 0.0 MiB session.close()
23 217.2 MiB 0.0 MiB print 'Done.'
24 221.0 MiB 3.8 MiB gc.dump_rpy_heap('bench.txt')
[3fd7569b13c5] {jit-summary
Tracing: 41 0.293192
Backend: 30 0.026873
TOTAL: 1615.665337
ops: 79116
recorded ops: 23091
calls: 2567
guards: 7081
opt ops: 5530
opt guards: 1400
forcings: 198
abort: trace too long: 2
abort: compiling: 0
abort: vable escape: 9
abort: bad loop: 0
abort: force quasi-immut: 0
nvirtuals: 9318
nvholes: 1113
nvreused: 6637
Total # of loops: 23
Total # of bridges: 8
Freed # of loops: 0
Freed # of bridges: 0
[3fd756c29302] jit-summary}
์ฌ๊ธฐ ๋คํ : https://gist.github.com/stas/ad597c87ccc4b563211a
์๊ฐ์๋ด์ด ๋์ ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค!
๋ฐ๋ผ์ ์ด๊ฒ์ ์ฌ์ฉ๋์ ์ฝ 100MB๋ฅผ ์ฐจ์งํฉ๋๋ค. ๋ ๊ณณ์ด ํด์
๊ทธ ์ค "์๋น ๋ฉ๋ชจ๋ฆฌ"์์ GC๋ ๋ค์ํ ์์
์ ์ํ ํ ์ ์์ต๋๋ค.
๋น GC ํ ๋น์์-์ด๋ OpenSSL์ ๋ด๋ถ
ํ ๋น. OpenSSL ๊ตฌ์กฐ์ธ์ง ํ์ธํ๋ ์ข์ ๋ฐฉ๋ฒ์ด ์๋์ง ๊ถ๊ธํฉ๋๋ค.
์ ์ถ๋๊ณ ์์ต๋๋ค. ์ฌ๊ธฐ์ TLS๋ก ํ
์คํธ์ค์ธ ๊ฒ์ด ์์ต๋๊น? ๊ทธ๋ ๋ค๋ฉด
TLS๊ฐ ์๋ ์ฌ์ดํธ๋ก ์๋ํด๋ณด๊ณ ์ฌํ๋๋์ง ํ์ธํ์ญ์์ค.
2014 ๋
11 ์ 8 ์ผ ํ ์์ผ ์คํ 5:38:04 Stas Suศcov [email protected]
์ผ๋ค :
๋ก๊ทธ:
๋ผ์ธ ๋ฒํธ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ฆ๊ฐ ๋ผ์ธ ์ฝํ ์ธ
16 22.0 MiB 0.0 MiB <strong i="18">@profile</strong> 17 def run(): 18 22.5 MiB 0.5 MiB session = requests.Session() 19 22.5 MiB 0.0 MiB print 'Starting...' 20 217.2 MiB 194.7 MiB multi_get(session, 3000) 21 217.2 MiB 0.0 MiB print("Finished first round...") 22 217.2 MiB 0.0 MiB session.close() 23 217.2 MiB 0.0 MiB print 'Done.' 24 221.0 MiB 3.8 MiB gc.dump_rpy_heap('bench.txt')
[3fd7569b13c5] {jit-summary
์ถ์ : 41 0.293192
๋ฐฑ์๋ : 30 0.026873
ํฉ๊ณ : 1615.665337
์์ : 79116
๊ธฐ๋ก ๋ ์์ : 23091
์ ํ : 2567
๊ฒฝ๋น์ : 7081
์ ํ ์์ : 5530
์ตํธ ๊ฐ๋ : 1400
๊ฐ์ ๋ ฅ : 198
์ค๋จ : ์ถ์ ์ด ๋๋ฌด ๊น : 2
์ค๋จ : ์ปดํ์ผ : 0
abort : vable escape : 9
abort : ์๋ชป๋ ๋ฃจํ : 0
abort : ๊ฐ์ ์ ์ฌ ๋ถ๋ณ : 0
nvirtuals : 9318
nvholes : 1113
nvreused : 6637
์ด ๋ฃจํ ์ : 23
์ด ๊ต๋ ์ : 8
ํด์ ๋ ๋ฃจํ ์ : 0
ํด์ ๋ ๋ธ๋ฆฌ์ง ์ : 0
[3fd756c29302] jit-summary}์ฌ๊ธฐ ๋คํ : https://gist.github.com/stas/ad597c87ccc4b563211a
์๊ฐ์๋ด์ด ๋์ ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค!
โ
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ฑฐ๋ GitHub์์ ํ์ธํ์ธ์.
https://github.com/kennethreitz/requests/issues/1685#issuecomment -62277822
.
@alex ,
@stas ๊ฐ์ด ๋ฒค์น ๋งํฌ๋ฅผ ์ํด ์ผ๋ฐ http (๋น SSL / TLS) ์ฐ๊ฒฐ์ ์ฌ์ฉํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ํน์๋ผ๋ @stas ์ ๋ฒค์น ๋งํฌ ์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ๊ณ ์ผ๋ฐ http ์ฐ๊ฒฐ์ ์ฌ์ฉํ์ฌ Mac (OSX 10.9.5 2.5GHz i5 8GB 1600MHz DDR3)์์ ๋ฏธ๋ฆฌ ์์ฑํ์ต๋๋ค.
๋์์ด๋๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋น๊ตํ ์ ์์ต๋๋ค (๊ทํ์ ์ง์นจ ์ฌ์ฉ).
https://gist.github.com/mhjohnson/a13f6403c8c3a3d49b8d
๋น์ ์ด ๋ฌด์จ ์๊ฐ์ํ๋์ง ์ ๊ฒ ์๋ ค์ฃผ์ธ์.
๊ฐ์ฌ,
-๋งคํธ
GitHub์ ์ ๊ท์์ด ๋๋ฌด ๋์จํฉ๋๋ค. ๋๋ ๊ทธ๊ฒ์ด ์์ ํ ์์ ๋์๋ค๊ณ ์๊ฐํ์ง ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ค์ ์ฌ๋ ๊ฒ์ ๋๋ค.
์๋ ํ์ธ์, ๋ฌธ์ ๊ฐ ์์์ ์ง์ ํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค. ์์ฒญ์ ์ฌ์ฉํ๋ ํฌ๋กค๋ฌ๊ฐ ์๊ณ ๋ค์ค ์ฒ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ํ๋ก์ธ์ค๊ฐ ์์ต๋๋ค. ๋ ์ด์์ ์ธ์คํด์ค๊ฐ ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๊ณ ์์ต๋๋ค. ๊ฒฐ๊ณผ ๋ฒํผ ๋๋ ์์ผ ์์ฒด์ ๋์๊ฐ์์ ์ ์์ต๋๋ค.
์ฝ๋ ์ํ์ ๋ณด๋ผ ์ ์๋์ง ๋๋ ์ ๋ณด์ ์ด๋ ๋ถ๋ถ์ด "๊ณต์ "(์ ์ถ)๋๋์ง ์๋ณํ๊ธฐ ์ํด ์ฐธ์กฐ ํธ๋ฆฌ๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ์๋ ค์ฃผ์ญ์์ค.
๊ฐ์ฌ
@barroca ๋ ๋ค๋ฅธ ๋ฌธ์ ์
๋๋ค. ์ค๋ ๋๊ฐ์ ์ธ์
์ ์ฌ์ฉํ๊ณ stream=True
์ฌ์ฉํ๊ณ ์์ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. ์ฝ๊ธฐ๋ฅผ ๋ง์น๊ธฐ ์ ์ ์๋ต์ ๋ซ๋ ๊ฒฝ์ฐ ์์ผ์ ํด๋น ๋ฐ์ดํฐ๊ฐ ์ฌ์ ํ์๋ ์ฐ๊ฒฐ ํ์ ๋ค์ ๋ฐฐ์น๋ฉ๋๋ค (์ฌ๋ฐ๋ฅด๊ฒ ๊ธฐ์ตํ๋ ๊ฒฝ์ฐ). ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ ๊ฐ์ฅ ์ต๊ทผ์ ์ฐ๊ฒฐ์ ์ ํํ๊ณ ์๋ฒ์์ ์บ์ ๋ ์๋ต์ ์์ ํ๋ ๊ฒ๋ ๊ทธ๋ด๋ฏํฉ๋๋ค. ์ด๋ ์ชฝ์ด๋ ์ด๊ฒ์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ํ๋ด๋ ๊ฒ์ด ์๋๋๋ค.
@ sigmavirus24 ๊ฐ์ฌํฉ๋๋ค Ian, ๋ง์ํ์ ๋๋ก ์ค๋ ๋ ์ ์ฒด์์ ์ธ์ ์
@barroca ๊ฑฑ์
์ด ๋ฌธ์ ์ ๋ํด ๋ ์ด์ ๋ถ๋ง์ด ์์์ผ๋ฉฐ ์ด์ ๋ํด ์ต์ ์ ๋คํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋๋ ๊ทธ๊ฒ์ ๋ค์ ์ด๊ณ ํ์ํ ๊ฒฝ์ฐ ๋ค์ ์กฐ์ฌํ๊ฒ๋์ด ๊ธฐ์ฉ๋๋ค
๊ทธ๋ ๋ค๋ฉด์ด ๋ฌธ์ ์ ํด๊ฒฐ์ฑ ์ ๋ฌด์์ ๋๊น?
@Makecodeeasy ๋๋ ์๊ณ ์ถ์ด
์ง๊ธ๊น์ง requests
๋ด ๋ฌธ์ ๋ ์ค๋ ๋๋ก๋ถํฐ ์์ ํ์ง ์๋ค๋ ๊ฒ์
๋๋ค.
๋ค๋ฅธ ์ค๋ ๋์ ๋ํด ๋ณ๋์ ์ธ์
์ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ต๋๋ค.
์บ์ ์๋ต์ ํ์ธํ๊ธฐ ์ํด ์๋ฐฑ๋ง ๊ฐ์ URL์ ๊ฑธ์ด๊ฐ๋ ์์ ์ด ์ฌ๊ธฐ๋ก ์ฐ๊ฒฐ๋ฉ๋๋ค.
requests
๊ฐ ThreadPoolExecutor
๋๋ threading
๊ณผ ์ํธ ์์ฉํ ๋ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ํฉ๋ฆฌ์ ์ด์์ผ๋ก ์ฆ๊ฐํ๋ค๋ ๊ฒ์ ์๊ฒ๋๋ฉด์,
๊ฒฐ๊ตญ ์ ๋ multiprocessing.Process
๋ฅผ ์ฌ์ฉํ์ฌ ์์
์๋ฅผ ๊ฒฉ๋ฆฌํ๊ณ ๊ฐ ์์
์์ ๋ํด ๋
๋ฆฝ์ ์ธ ์ธ์
์ ๊ฐ์ต๋๋ค.
@AndCycle ๊ทธ๋ฌ๋ฉด ๋ฌธ์ ๊ฐ ์ฌ๊ธฐ์ ์์ต๋๋ค. ์ด ํน์ ๋ฉ๋ชจ๋ฆฌ ๋์ ์ฌ๋ก๋ฅผ ์์ ํ๊ธฐ ์ํด ๋ณํฉ ๋ PR์ด ์์ต๋๋ค. ์ฃผ์์ ํ ์คํธ๊ฐ ์๊ธฐ ๋๋ฌธ์ ํ๊ทํ์ง ์์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทํ์ ๋ฌธ์ ๋ ์์ ํ ๋ค๋ฅธ ๊ฒ ๊ฐ์ต๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
์ด ๋ฌธ์ ์ ๋ํด ๋ ์ด์ ๋ถ๋ง์ด ์์์ผ๋ฉฐ ์ด์ ๋ํด ์ต์ ์ ๋คํ๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋๋ ๊ทธ๊ฒ์ ๋ค์ ์ด๊ณ ํ์ํ ๊ฒฝ์ฐ ๋ค์ ์กฐ์ฌํ๊ฒ๋์ด ๊ธฐ์ฉ๋๋ค