Requests: ๊ฐ€๋Šฅํ•œ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜

์— ๋งŒ๋“  2013๋…„ 10์›” 17์ผ  ยท  53์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: psf/requests

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..."

ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๋˜์ง€ ์•Š๋Š” ํ•œ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์€ ๋–จ์–ด์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฒ„๊ทธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ์‚ฌ์šฉ์ž ์˜ค๋ฅ˜์ž…๋‹ˆ๊นŒ?

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋” ์ด์ƒ ๋ถˆ๋งŒ์ด ์—†์—ˆ์œผ๋ฉฐ ์ด์— ๋Œ€ํ•ด ์ตœ์„ ์„ ๋‹คํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ๋‹ค์‹œ ์—ด๊ณ  ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋‹ค์‹œ ์กฐ์‚ฌํ•˜๊ฒŒ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค

๋ชจ๋“  53 ๋Œ“๊ธ€

์ด ๋ฌธ์ œ๋ฅผ ์ œ๊ธฐํ•˜๊ณ  ์ž์„ธํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

๋งํ•ด ๋ด์š”, ์–ด๋–ค ์‹œ์ ์—์„œ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๊ฐ์†Œํ•˜๋Š” ๊ฒƒ์„ ๋ณธ ์ ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ์ค„์–ด๋“œ๋Š” ๊ฒƒ์„ ๋ณด์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ํŒŒ์ด์ฌ์˜ ๊ฐ€๋น„์ง€ ์ˆ˜์ง‘๊ธฐ์™€ ๊ด€๋ จ์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ–ˆ๊ณ  ์•„๋งˆ๋„ ์‹œ์ž‘ํ•  ๊ธฐํšŒ๊ฐ€ ์—†์—ˆ์„ ๊ฒƒ์ด๋ฏ€๋กœ ๋‹ค์šด๋กœ๋“œ ํ•  ๋•Œ๋งˆ๋‹ค 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 ๊ฐœ์˜ ์ฃผ์„์„ ๋‹ฌ๊ณ  ๋‹ค์Œ์„ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค.
requests 2 ๊ฐœ์˜ ์ฐธ์กฐ๊ฐ€ ์žˆ์Œ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์‹ ๋ขฐํ•  ์ˆ˜์—†๋Š” sys.getrefcount ์ž‘๋™ ๋ฐฉ์‹์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๊ทธ๊ฒƒ์€ ๋ถ‰์€ ์ฒญ์–ด์ž…๋‹ˆ๋‹ค. urllib3.response.HTTPResponse ์—๋Š” _original_response ๋ฐ _fp ์žˆ์Šต๋‹ˆ๋‹ค. _HTTPConection__response ์™€ ๊ฒฐํ•ฉํ•˜๋ฉด ์„ธ ๊ฐœ์˜ ์‹ฌํŒ์ด ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ, urllib3.response.HTTPResponse ์ด _pool ๋„์— ์˜ํ•ด ์ฐธ์กฐ๋˜๋Š” ์†์„ฑ PoolManager . ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์š”์ฒญ์„ ๋งŒ๋“œ๋Š” ๋ฐ ์‚ฌ์šฉ ๋œ HTTPAdapter ์—๋Š” Response ์š”์ฒญ ๋ฐ˜ํ™˜์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์—ฌ๊ธฐ์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ์‹๋ณ„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

requests

์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ : 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.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
.

@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 ๋‚˜๋Š”์ด์žˆ์–ด :

socket

ํฅ๋ฏธ๋กœ์šด ์ ์€ 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 ๋Š” ๋‹ค์Œ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

socket-after

๋”ฐ๋ผ์„œ SSL ์†Œ์ผ“์— ๋Œ€ํ•œ ํ•˜๋‚˜์˜ ์ฐธ์กฐ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, s._sock ๋ณด๋ฉด ๊ธฐ๋ณธ socket.socket ๊ฐ€ ๋‹ซํž™๋‹ˆ๋‹ค.

์žฅ๊ธฐ ์‹คํ–‰ ๋ฒค์น˜ ๋งˆํฌ๋ฅผ ์‹คํ–‰ ํ•œ ํ›„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‚ฌ์‹ค์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.

  • close() ํ˜ธ์ถœํ•˜๋ฉด ๋„์›€์ด๋ฉ๋‹ˆ๋‹ค!
  • ์—ฌ๋Ÿฌ ์š”์ฒญ์„ ์‹คํ–‰ํ•˜๋Š” ์‚ฌ์šฉ์ž๋Š” Session ์„ (๋ฅผ) ์‚ฌ์šฉํ•˜๊ณ  ์™„๋ฃŒ ํ›„ ์ œ๋Œ€๋กœ ๋‹ซ์•„์•ผํ•ฉ๋‹ˆ๋‹ค. # 2326์„ ๋ณ‘ํ•ฉํ•˜์‹ญ์‹œ์˜ค
  • PyPy ์‚ฌ์šฉ์ž๋Š” JIT์—†์ด ๋” ์ข‹์Šต๋‹ˆ๋‹ค! ๋˜๋Š” 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์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃผ์œ„์— ํ…Œ์ŠคํŠธ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํšŒ๊ท€ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ท€ํ•˜์˜ ๋ฌธ์ œ๋Š” ์™„์ „ํžˆ ๋‹ค๋ฅธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰