μλμ λΉ λ₯Έ AsyncScraper ν΄λμ€λ₯Ό μμ±νμ΅λλ€.
import logging, datetime, time
import aiohttp
import asyncio
import uvloop
# asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger.addHandler(logging.StreamHandler())
class AsyncScraper(object):
headers = {"User-Agent" : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36'}
def __init__(self, max_connections=1000, timeout=10):
self.max_connections = max_connections
self.timeout = timeout
async def get_response(self, url, session):
with aiohttp.Timeout(timeout=self.timeout):
async with session.get(url, allow_redirects=True, headers=AsyncScraper.headers, timeout=self.timeout) as response:
try:
content = await response.text()
return {'error': "", 'status': response.status, 'url':url, 'content': content, 'timestamp': str(datetime.datetime.utcnow())}
except Exception as err:
return {'error': err, 'status': "", 'url':url, 'content': "", 'timestamp': str(datetime.datetime.utcnow())}
finally:
response.close()
def get_all(self, urls):
loop = asyncio.get_event_loop()
with aiohttp.ClientSession(loop=loop, connector=aiohttp.TCPConnector(keepalive_timeout=10, limit=self.max_connections, verify_ssl=False)) as session:
tasks = asyncio.gather(*[self.get_response(url, session) for url in urls], return_exceptions=True)
results = loop.run_until_complete(tasks)
return results
def chunks(l, n):
for i in range(0, len(l), n):
yield l[i:i + n]
def process_urls(urls, chunk_size=1000):
scraper = AsyncScraper()
results = []
t0 = time.time()
for i, urls_chunk in enumerate(chunks(sorted(set(urls)), chunk_size)):
t1 = time.time()
result = scraper.get_all(urls_chunk)
success_size = len( [_ for _ in result if ((isinstance(_, Exception) is False) and (_['status']==200)) ] )
results.extend(result)
logger.debug("batch {} => success: {} => iteration time: {}s => total time: {}s => total processed {}".format(i+1, success_size, time.time()-t1, time.time()-t0, len(results)))
return results
λ κ°μ§ μ£Όμ λ¬Έμ κ° μμ΅λλ€.
λ¨μ URL λͺ©λ‘ (μ : get_all λ©μλλ₯Ό ν΅ν΄)μ 100kλ‘ μ λ¬νλ©΄ μ€λ₯κ° λ²λν©λλ€.
2017-04-17 15 : 50 : 53,541-asyncio-ERROR-SSL μ μ‘μ μΉλͺ
μ μΈ μ€λ₯
μ€ν κ³νμ:
μ μ‘ : <_SelectorSocketTransport λ«κΈ° fd = 612 read = idle write =
μ μΆμ (κ°μ₯ μ΅κ·Ό νΈμΆ λ§μ§λ§) :
_process_write_backlogμ νμΌ "/Users/vgoklani/anaconda3/lib/python3.6/asyncio/sslproto.py", 639 ν
ssldata = self._sslpipe.shutdown (self._finalize)
νμΌ "/Users/vgoklani/anaconda3/lib/python3.6/asyncio/sslproto.py", μ€ 151, μ’
λ£ μ€
RuntimeError ( 'shutdown in progress') λ°μ
RuntimeError : μ’
λ£ μ§ν μ€
κ·Έλ° λ€μ URLμ 1,000 κ° λ¨μλ‘ μΌκ΄ μ²λ¦¬νκ³ μΌκ΄ μ²λ¦¬ κ°μ μλ΅ μκ°μ μΈ‘μ νμ΅λλ€. κ·Έλ¦¬κ³ μκ°μ λ°λ₯Έ μ±λ₯ μ νλ₯Ό λͺ ννκ² μΈ‘μ ν μμμμ΅λλ€ (μλ μ°Έμ‘°). κ²λ€κ° μκ°μ΄ μ§λ¨μ λ°λΌ μ€λ₯ μκ° μ¦κ°νμ΅λλ€ ... λ΄κ° λ μλͺ»νκ³ μλκ°?
λ°λ³΅ 0μ 16.991 μ΄μ μλ£λμμ΅λλ€.
39.376 μ΄μ λ°λ³΅ 1 μλ£
λ°λ³΅ 2λ 35.656 μ΄μ μλ£λμμ΅λλ€.
19.716sμμ λ°λ³΅ 3 μν
29.331sμμ λ°λ³΅ 4 μν
19.708sμμ λ°λ³΅ 5 μν
19.572 μ΄μ 6 λ² λ°λ³΅
29.907sμμ λ°λ³΅ 7 μν
23.379 μ΄μ 8 λ² λ°λ³΅
21.762 μ΄μ 9 λ² λ°λ³΅
22.091 μ΄μ 10 λ² λ°λ³΅
22.940 μ΄μ 11 λ² λ°λ³΅
31.285 μ΄μ 12 λ² λ°λ³΅
λ°λ³΅ 13μ 24.549 μ΄μ μλ£λμμ΅λλ€.
λ°λ³΅ 14λ 26.297 μ΄μ μλ£λμμ΅λλ€.
23.816 μ΄μ 15 λ² λ°λ³΅
29.094 μ΄μ 16 λ² λ°λ³΅
24.885 μ΄μ 17 λ² λ°λ³΅
26.456 μ΄μ 18 λ² λ°λ³΅
27.412sμμ 19 λ² λ°λ³΅
29.969 μ΄μ 20 λ² λ°λ³΅
28.503 μ΄μ 21 λ² λ°λ³΅
28.699 μ΄μ 22 λ² λ°λ³΅
31.570 μ΄μ 23 λ² λ°λ³΅
31.898sμμ 26 λ² λ°λ³΅
33.553 μ΄μ 27 λ² λ°λ³΅
34.022 μ΄μ 28 λ² λ°λ³΅
33.866 μ΄μ 29 λ² λ°λ³΅
36.351sμμ 30 λ² λ°λ³΅
40.060 μ΄μ 31 λ² λ°λ³΅
35.523 μ΄μ 32 λ² λ°λ³΅
36.607 μ΄μ 33 λ² λ°λ³΅
36.325 μ΄μ 34 λ² λ°λ³΅
38.425 μ΄μ 35 λ² λ°λ³΅
39.106 μ΄μ 36 λ² λ°λ³΅
38.972 μ΄μ 37 λ² λ°λ³΅
39.845 μ΄μ 38 λ² λ°λ³΅
40.393sμμ 39 ν λ°λ³΅
40.734 μ΄μ 40 λ² λ°λ³΅
47.799 μ΄μ 41 λ² λ°λ³΅
43.070sμμ μνλλ λ°λ³΅ 42
43.365 μ΄μ 43 λ² λ°λ³΅
42.081 μ΄μ 44 λ² λ°λ³΅
44.118 μ΄μ 45 λ² λ°λ³΅
44.955 μ΄μ 46 λ² λ°λ³΅
45.400 μ΄μ 47 λ² λ°λ³΅
45.987sμμ 48 λ² λ°λ³΅
46.041sμμ μν λ λ°λ³΅ 49
45.899 μ΄μ 50 ν λ°λ³΅
49.008sμμ μνλλ λ°λ³΅ 51
49.544 μ΄μ 52 ν λ°λ³΅
55.432 μ΄μ 53 λ² λ°λ³΅
52.590 μ΄μ 54 λ² λ°λ³΅
50.185 μ΄μ 55 λ² λ°λ³΅
52.858 μ΄μ 56 λ² λ°λ³΅
52.698sμμ 57 ν λ°λ³΅
53.048 μ΄μ 58 ν λ°λ³΅
54.120 μ΄μ 59 λ² λ°λ³΅
54.151 μ΄μ 60 λ² λ°λ³΅
55.465 μ΄μ 61 λ² λ°λ³΅
56.889 μ΄μ 62 λ² λ°λ³΅
56.967 μ΄μ 63 λ² λ°λ³΅
57.690 μ΄μ 64 λ² λ°λ³΅
57.052 μ΄μ 65 λ² λ°λ³΅
67.214sμμ μνλλ λ°λ³΅ 66
58.457 μ΄μ 67 λ² λ°λ³΅
60.882 μ΄μ 68 λ² λ°λ³΅
58.440 μ΄μ 69 λ² λ°λ³΅
60.755 μ΄μ 70 λ² λ°λ³΅
58.043sμμ μνλλ λ°λ³΅ 71
65.076 μ΄μ 72 λ² λ°λ³΅
63.371 μ΄μ 73 λ² λ°λ³΅
62.800 μ΄μ 74 λ² λ°λ³΅
62.419 μ΄μ 75 λ² λ°λ³΅
61.376 μ΄μ 76 λ² λ°λ³΅
63.164sμμ 77 λ² λ°λ³΅
65.443 μ΄μ 78 λ² λ°λ³΅
64.616 μ΄μ 79 λ² λ°λ³΅
69.544 μ΄μ 80 λ² λ°λ³΅
68.226sμμ μνλλ λ°λ³΅ 81
78.050 μ΄μ 82 λ² λ°λ³΅
67.871 μ΄μ 83 λ² λ°λ³΅
69.780 μ΄μ 84 λ² λ°λ³΅
67.812 μ΄μ 85 λ² λ°λ³΅
68.895 μ΄μ 86 λ² λ°λ³΅
71.086sμμ μν λ λ°λ³΅ 87
68.809 μ΄μμ μν λ λ°λ³΅ 88
70.945 μ΄μ 89 λ² λ°λ³΅
72.760 μ΄μ 90 λ² λ°λ³΅
71.773sμμ μνλλ λ°λ³΅ 91
72.522 μ΄μ 92 λ² λ°λ³΅
μ¬κΈ°μ μκ°μ 1,000 κ°μ URLμ μ²λ¦¬νλ λ°λ³΅ μκ°μ ν΄λΉν©λλ€. μ‘°μΈνμμμ€. κ°μ¬
μ΄λ€ λ²μ μ aiohttpλ₯Ό μ¬μ©νμλκΉ? μ΄λ¦° TCP μ°κ²°λ νμΈνμμμ€. μ«μκ° μ¦κ°ν©λκΉ?
2017 λ 4 μ 17 μΌ μ€ν 12:46μ Vishal Goklani [email protected]μ΄ λ€μκ³Ό κ°μ΄ μΌμ΅λλ€.
μλμ λΉ λ₯Έ AsyncScraper ν΄λμ€λ₯Ό μμ±νμ΅λλ€.
κ°μ Έ μ€κΈ° λ‘κΉ , λ μ§ μκ°
μμ aiohttp
κ°μ Έ μ€κΈ° asyncio
uvloop κ°μ Έ μ€κΈ°asyncio.set_event_loop_policy (uvloop.EventLoopPolicy ())
λ‘κ±° = logging.getLogger (__ name__)
logger.setLevel (logging.INFO)
logging.basicConfig (νμ = '% (asctime) s-% (name) s-% (levelname) s-% (message) s')
logger.addHandler (logging.StreamHandler ())ν΄λμ€ AsyncScraper (κ°μ²΄) :
headers = { "User-Agent": 'Mozilla / 5.0 (Macintosh, Intel Mac OS X 10_9_2) AppleWebKit / 537.36 (Geckoμ κ°μ KHTML) Chrome / 34.0.1847.131 Safari / 537.36'}
def __init __ (self, number_workers = 100, max_connections = 1000, timeout = 10) :
self.number_workers = number_workers
self.max_connections = max_connections
self.timeout = μκ° μ΄κ³Ό
self.work_queue = asyncio.Queue ()
self.cookie_jar = aiohttp.CookieJar (unsafe = True)
self.session = aiohttp.ClientSession (connector = aiohttp.TCPConnector (limit = self.max_connections, verify_ssl = False), cookie_jar = self.cookie_jar)def __del __ (self) :
self.session.close ()async def get_response (self, url) :
μν:
aiohttp.Timeout (self.timeout) μ¬μ© :
μλ΅μΌλ‘ self.session.get (url, allow_redirects = True, headers = AsyncScraper.headers)μ λΉ λκΈ°ν :
content = await response.text ()
return { 'error': "", 'status': response.status, 'url': url, 'content': content, 'timestamp': str (datetime.datetime.utcnow ())}
μμΈλ₯Ό μ μΈνκ³ μ€λ₯ :
return { 'error': err, 'status': "", 'url': url, 'content': "", 'timestamp': str (datetime.datetime.utcnow ())}async def consumer (self, worker_id) :
κ²°κ³Ό = []
self.work_queue.empty ()λ μλμ§λ§ :
queue_url = self.work_queue.get () λκΈ°logger.debug("processing {} from worker_{}".format(queue_url, worker_id)) response = await self.get_response(queue_url) logger.debug("received {} from worker_{}".format(queue_url, worker_id)) if response['error'] is "": results.append(response) logger.debug("finished processing {} urls via worker_{}".format(len(results), worker_id)) return results
def get_all (self, urls) :
[urlμ urlμ λν self.work_queue.put_nowait (url)]
tasks = asyncio.gather (* [self.consumer (worker_id) for worker_id in range (self.number_workers)], return_exceptions = True)
루ν = asyncio.get_event_loop ()
κ²°κ³Ό = loop.run_until_complete (μμ )
return [__ for _ in results for __ in _]
λ κ°μ§ μ£Όμ λ¬Έμ κ° μμ΅λλ€.λ¨μ URL λͺ©λ‘ (μ : 100k)μ μ λ¬νλ©΄ μκ° μ΄κ³Ό μ€λ₯κ° λ°μν©λλ€.
κ·Έλ° λ€μ URLμ 1,000 κ° λ¨μλ‘ μΌκ΄ μ²λ¦¬νκ³ μΌκ΄ μ²λ¦¬ κ°μ μλ΅ μκ°μ μΈ‘μ νμ΅λλ€. κ·Έλ¦¬κ³ μκ°μ΄ μ§λ¨μ λ°λΌ μ±λ₯μ΄ μ νλλ€λ κ²μ λͺ ννκ² μΈ‘μ ν μμμμ΅λλ€.
λ°λ³΅ 0μ 16.991 μ΄μ μλ£λμμ΅λλ€.
39.376 μ΄μ λ°λ³΅ 1 μλ£
λ°λ³΅ 2λ 35.656 μ΄μ μλ£λμμ΅λλ€.
19.716sμμ λ°λ³΅ 3 μν
29.331sμμ λ°λ³΅ 4 μν
19.708sμμ λ°λ³΅ 5 μν
19.572 μ΄μ 6 λ² λ°λ³΅
29.907sμμ λ°λ³΅ 7 μν
23.379 μ΄μ 8 λ² λ°λ³΅
21.762 μ΄μ 9 λ² λ°λ³΅
22.091 μ΄μ 10 λ² λ°λ³΅
22.940 μ΄μ 11 λ² λ°λ³΅
31.285 μ΄μ 12 λ² λ°λ³΅
λ°λ³΅ 13μ 24.549 μ΄μ μλ£λμμ΅λλ€.
λ°λ³΅ 14λ 26.297 μ΄μ μλ£λμμ΅λλ€.
23.816 μ΄μ 15 λ² λ°λ³΅
29.094 μ΄μ 16 λ² λ°λ³΅
24.885 μ΄μ 17 λ² λ°λ³΅
26.456 μ΄μ 18 λ² λ°λ³΅
27.412sμμ 19 λ² λ°λ³΅
29.969 μ΄μ 20 λ² λ°λ³΅
28.503 μ΄μ 21 λ² λ°λ³΅
28.699 μ΄μ 22 λ² λ°λ³΅
31.570 μ΄μ 23 λ² λ°λ³΅
31.898sμμ 26 λ² λ°λ³΅
33.553 μ΄μ 27 λ² λ°λ³΅
34.022 μ΄μ 28 λ² λ°λ³΅
33.866 μ΄μ 29 λ² λ°λ³΅
36.351sμμ 30 λ² λ°λ³΅
40.060 μ΄μ 31 λ² λ°λ³΅
35.523 μ΄μ 32 λ² λ°λ³΅
36.607 μ΄μ 33 λ² λ°λ³΅
36.325 μ΄μ 34 λ² λ°λ³΅
38.425 μ΄μ 35 λ² λ°λ³΅
39.106 μ΄μ 36 λ² λ°λ³΅
38.972 μ΄μ 37 λ² λ°λ³΅
39.845 μ΄μ 38 λ² λ°λ³΅
40.393sμμ 39 ν λ°λ³΅
40.734 μ΄μ 40 λ² λ°λ³΅
47.799 μ΄μ 41 λ² λ°λ³΅
43.070sμμ μνλλ λ°λ³΅ 42
43.365 μ΄μ 43 λ² λ°λ³΅
42.081 μ΄μ 44 λ² λ°λ³΅
44.118 μ΄μ 45 λ² λ°λ³΅
44.955 μ΄μ 46 λ² λ°λ³΅
45.400 μ΄μ 47 λ² λ°λ³΅
45.987sμμ 48 λ² λ°λ³΅
46.041sμμ μν λ λ°λ³΅ 49
45.899 μ΄μ 50 ν λ°λ³΅
49.008sμμ μνλλ λ°λ³΅ 51
49.544 μ΄μ 52 ν λ°λ³΅
55.432 μ΄μ 53 λ² λ°λ³΅
52.590 μ΄μ 54 λ² λ°λ³΅
50.185 μ΄μ 55 λ² λ°λ³΅
52.858 μ΄μ 56 λ² λ°λ³΅
52.698sμμ 57 ν λ°λ³΅
53.048 μ΄μ 58 ν λ°λ³΅
54.120 μ΄μ 59 λ² λ°λ³΅
54.151 μ΄μ 60 λ² λ°λ³΅
55.465 μ΄μ 61 λ² λ°λ³΅
56.889 μ΄μ 62 λ² λ°λ³΅
56.967 μ΄μ 63 λ² λ°λ³΅
57.690 μ΄μ 64 λ² λ°λ³΅
57.052 μ΄μ 65 λ² λ°λ³΅
67.214sμμ μνλλ λ°λ³΅ 66
58.457 μ΄μ 67 λ² λ°λ³΅
60.882 μ΄μ 68 λ² λ°λ³΅
58.440 μ΄μ 69 λ² λ°λ³΅
60.755 μ΄μ 70 λ² λ°λ³΅
58.043sμμ μνλλ λ°λ³΅ 71
65.076 μ΄μ 72 λ² λ°λ³΅
63.371 μ΄μ 73 λ² λ°λ³΅
62.800 μ΄μ 74 λ² λ°λ³΅
62.419 μ΄μ 75 λ² λ°λ³΅
61.376 μ΄μ 76 λ² λ°λ³΅
63.164sμμ 77 λ² λ°λ³΅
65.443 μ΄μ 78 λ² λ°λ³΅
64.616 μ΄μ 79 λ² λ°λ³΅
69.544 μ΄μ 80 λ² λ°λ³΅
68.226sμμ μνλλ λ°λ³΅ 81
78.050 μ΄μ 82 λ² λ°λ³΅
67.871 μ΄μ 83 λ² λ°λ³΅
69.780 μ΄μ 84 λ² λ°λ³΅
67.812 μ΄μ 85 λ² λ°λ³΅
68.895 μ΄μ 86 λ² λ°λ³΅
71.086sμμ μν λ λ°λ³΅ 87
68.809 μ΄μμ μν λ λ°λ³΅ 88
70.945 μ΄μ 89 λ² λ°λ³΅
72.760 μ΄μ 90 λ² λ°λ³΅
71.773sμμ μνλλ λ°λ³΅ 91
72.522 μ΄μ 92 λ² λ°λ³΅μ¬κΈ°μ μκ°μ 1,000 κ°μ URLμ μ²λ¦¬νλ λ°λ³΅ μκ°μ ν΄λΉν©λλ€. μ‘°μΈνμμμ€. κ°μ¬
β
μ΄ μ€λ λλ₯Ό ꡬλ νκΈ° λλ¬Έμμ΄ λ©μμ§κ° μ μ‘λμμ΅λλ€.
μ΄ μ΄λ©μΌμ μ§μ λ΅μ₯νκ±°λ GitHub https://github.com/aio-libs/aiohttp/issues/1821 μμ 보거λ https://github.com/notifications/unsubscribe-auth/AAkjzsPpQtk7SDgKmTUKUblSZ0Bfu1lVks5rw8GTgaJpZM4M_fXe μμ μ€λ λλ₯Ό μμκ±°
μ λ '2.0.5'λ₯Ό μ¬μ©νκ³ μμ΅λλ€. μ΄λ¦° TCP μ°κ²°μ μ΄λ»κ² νμΈν©λκΉ?
μ΄λ€ λ²μ μ νμ΄μ¬μ μ¬μ©νμλκΉ?
μ°κ²°μ νμΈνλ €λ©΄ "netstat"λͺ λ Ήμ μ¬μ©νμ¬ λͺ κ°μ§ μΈ‘μ μ μννμμμ€.
2017 λ 4 μ 17 μΌ μ€ν 12μ 50 λΆμ Vishal Goklani [email protected] μ λ€μκ³Ό κ°μ΄ μΌμ΅λλ€.
μ λ '2.0.5'λ₯Ό μ¬μ©νκ³ μμ΅λλ€. μ΄λ¦° TCP μ°κ²°μ μ΄λ»κ² νμΈν©λκΉ?
β
λκΈμ λ¬μ κΈ° λλ¬Έμ μμ ν κ²μ λλ€.
μ΄ μ΄λ©μΌμ μ§μ λ΅μ₯νκ±°λ GitHub https://github.com/aio-libs/aiohttp/issues/1821#issuecomment-294571709 μμ 보거λ https://github.com/notifications/unsubscribe-auth/ μ€λ λλ₯Ό μμκ±°ν©λλ€.
νμ΄μ¬ 3.6.0μ μ¬μ©νκ³ μμ΅λλ€.
μ½λμμ λͺ λ°±ν μ€μλ₯Όνκ³ μμ΅λκΉ?
λλ λͺ
λ°±ν κ²μ λ³΄μ§ λͺ»νλ€. aiohttpμ μ΄λ€ λΆλΆμ΄ λ¬Έμ μ μμΈμΈμ§ λͺ
νννκ³ μΆμ΅λλ€.
λν python3.6μ SSL μμΌμ λμΆν©λλ€.
2017 λ 4 μ 17 μΌ μ€ν 3:02μ Vishal Goklani [email protected] μ λ€μκ³Ό κ°μ΄ μΌμ΅λλ€.
μ½λμμ λͺ λ°±ν μ€μλ₯Όνκ³ μμ΅λκΉ?
β
λκΈμ λ¬μ κΈ° λλ¬Έμ μμ ν κ²μ λλ€.
μ΄ μ΄λ©μΌμ μ§μ λ΅μ₯νκ±°λ GitHub https://github.com/aio-libs/aiohttp/issues/1821#issuecomment-294607188 μμ 보거λ https://github.com/notifications/unsubscribe-auth/ μ€λ λλ₯Ό μμκ±°ν©λλ€.
ν μ€νΈλ₯Ό λκΈ° μν΄ μ κ° νΉλ³ν ν μμλ μΌμ΄ μμ΅λκΉ? netstatλ‘ λ¬΄μμ μνλμ§ μ λͺ¨λ₯΄κ² μ΅λλ€.
μ΄λ¦° μ°κ²° μκ° μ¦κ°ν©λκΉ?
Linuxμ κ²½μ°-첫 λ²μ§Έ, λ λ²μ§Έ, μ€κ° λ° λ§μ§λ§ URL μ²ν¬λ₯Ό μ²λ¦¬νλ λμ μ½μμμ μ€ν
PID = pid_of_server
netstat -npt | grep $ PID / | νμ₯μ€ -l
λλ μ΄κ²μ λ§λ¬λ€. μ νμ΄ 100 μΈ TCPConnecterλ₯Ό μ¬μ©νλ 10,000 κ°μ λΉλκΈ° μμ²μ μ²μμλ μ μμλμ§λ§ μ¦μ netstat
λ₯Ό ν΅ν΄ νμλλ μ°κ²°μ΄ μ¬λΌμ§λλ€. κΈ΄ 꼬리μ΄μ§λ§ κ²°κ΅ 0
μ λλ¬νκ³ λλ¨Έμ§ λͺ¨λ μμ²μ΄ λ°μν©λλ€.
asyncio.Semaphore
λ₯Ό μ¬μ©νμ¬ μ ν μλλ₯Ό μ§μ νλ©΄μ΄ λ¬Έμ λ₯Ό ν΄κ²°ν μμλ κ² κ°μ΅λλ€ ( netstat
λ³΄κ³ κΈ°κ° λμ μ νμ κ°κΉμ). λλ λΉκ΅μ aio
pythonμ μ¬μ©νμ§λ§, κ·Έλμ λΉμ©μ΄ μΌλ§μΈμ§ νμ€νμ§ μμ΅λλ€.
νΈμ§ : Python 3.5.2κ°μλ Ubuntu 16.04μμ λ€μμ μ¬μ©νμ¬ λ³΄μμ΅λλ€.
aiohttp==2.0.7
appdirs==1.4.3
async-timeout==1.2.1
chardet==3.0.3
multidict==2.1.5
packaging==16.8
pyparsing==2.2.0
six==1.10.0
yarl==0.10.2
@vgoklani @mal μκ° μ΄κ³Όλ₯Ό λΉνμ±ννλ λμΌν ν μ€νΈλ₯Ό μλν΄ λ³Ό μ μμ΅λκΉ? μ΄μμ μΈ κ²μ μλμ§λ§ μ€λ₯κ° μμ μ·¨μ λλ λ€λ₯Έ μ΄μ λ‘ μΈν κ²μΈμ§ νμΈνλ κ²μ λλ€.
session.request
νΈμΆμμ timeout=None
λ₯Ό μ¬μ©νμ¬ λ€μ μ€ννμ§λ§ λμμ΄ λ³κ²½λμ§ μμ κ² κ°μΌλ©° μ°κ²°μ΄ μ¬μ ν λμ΄μ‘μ΅λλ€. ν
μ€νΈ μΌμ΄μ€λ₯Ό μ½κ° μ 리νκ³ λ‘컬μμ μ¬ν ν μ μλλ‘νμ΅λλ€. λμμ΄λκΈ°λ₯Ό λ°λλλ€ : https://gist.github.com/mal/53506cd81fa27c39afc4f7fbef7b7b5a
FWIWλ λ‘컬μμ asyncio.Semaphoreλ₯Ό μ¬μ©νμ¬ μ½ 4 λ°° λ λΉ λ₯΄κ² μμ²μ μ€νν©λλ€.
3.5.2λ‘ μλνμ¬ SSL λμΆκ³Ό κ΄λ ¨μ΄ μλμ§ νμΈνλ κ²μ΄ μ’μ΅λλ€. λν μ¬λ¬ μμ μ λ³λ ¬λ‘ μννκΈ° μν΄ https://gist.github.com/thehesiod/7081ab165b9a0d4de2e07d321cc2391d μ κ°μ ν¨ν΄μ μ¬μ©ν©λλ€
@thehesiod 3.5.2λ₯Ό μ€ννλ λμΌν λ¬Έμ κ° μμ΅λλ€. μ΄ μ€ λν«μ λ°€μ μ€ννμ΅λλ€.
async def page_get(url):
while True:
try:
t = time.time()
async with aiohttp.request("GET", url) as req:
resp_content = await req.read()
print(time.time() - t, "seconds taken")
except Exception as e:
print(str(datetime.datetime.now()) + " - Connection error: {0}".format(str(e)))
await asyncio.sleep(2)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait([page_get('http://www.google.com')]))
0.05777549743652344 μ΄ μμ
0.05143165588378906 μ΄ κ±Έλ¦Ό
0.045487165451049805 μ΄ κ±Έλ¦Ό
0.0573725700378418 μ΄ μμ
0.049524545669555664 μ΄ κ±Έλ¦Ό
μ€λ λ΄κ° κ·Έκ²μ νμΈνμ λ λλ λ€μμ μ»μμ΅λλ€.
1.3857007026672363 μ΄ κ±Έλ¦Ό
0.47487688064575195 μ΄ κ±Έλ¦Ό
0.23848772048950195 μ΄ κ±Έλ¦Ό
2.2507810592651367 μ΄ μμ
0.25020551681518555 μ΄ κ±Έλ¦Ό
0.12477540969848633 μ΄ μμ
2.4836790561676025 μ΄ κ±Έλ¦Ό
1.1492459774017334 μ΄ κ±Έλ¦Ό
@thehesiod λ΄κ° 3.5.2
, 3.5.3
μ λν΄ κ²μ ν ν
μ€νΈ μΌμ΄μ€λ₯Ό μ€ννκ³ 3.6.1
μ’μ μΈ‘μ κ°μ λν΄ λͺ¨λ 7k λ§ν¬ μ£Όλ³μμ λμΌν μ νλ₯Ό 보μ¬μ€λλ€.
pyvmmonitorλ‘ λΉ λ₯΄κ³ λ릴 λ μ€λ μ·μ μ°μ΄λ λ κΉμ?
μ΄λ€ μ΄μ λ‘ λ pyvmmonitorλ 곡μ μΉμ§ μμ΅λλ€ (X11 λ¬Έμ , Python λͺ¨λ λλ½, μΈκΈλμ§ μμ 곡μ κ°μ²΄ νμΌ λλ½). λμμ΄λλ€λ©΄ cProfilesλ₯Ό μ 곡νκ²λμ΄ κΈ°μ©λλ€.νμ§λ§ pyvmmonitor μΆλ ₯μ΄ νμν κ²½μ° κ°μ₯ μ’μ λ°©λ²μ ν μ€νΈ μΌμ΄μ€λ₯Ό μ§μ μ€ννλ κ² κ°μ΅λλ€. μ£μ‘ν©λλ€.
λ¬Όλ‘ κ·Έλ κ² λ§νμλ§μ 무μμ΄ μλͺ»λμλμ§ κΉ¨λ¬μμ΅λλ€. > _ <
μ΄μ ν μ€νΈ μΌμ΄μ€ μλ λΉ λ₯΄κ³ λλ¦° λ³ν (fast = semaphore, slow = limit param)κ³Ό κ°κ° μ€νλλ pstat νμΌμ΄ ν¬ν¨λ©λλ€.
μ’μ΅λλ€. λμμ΄ λ κ²μ λλ€. κ°μ¬ν©λλ€!
λλ¦° κ²½μ°μλ μ΄λ€ μ΄μ λ‘ λ μκ°μ 60 %κ° select.epoll
μλΉλ©λλ€. λ
ΈνΈλΆ λͺ¨λν°μμλ μμ§ λΉ λ₯Έ μΌμ΄μ€μμλ μ°Ύμ μ μμ΅λλ€. λν slow.pyμμ μ°κ²°μ νλ‘ λ°ννκΈ° μ μ μ°κ²°μ λΉμ°μ§ μλ κ²μΌλ‘ λνλ¬μ΅λλ€ (λ³Έλ¬Έ μ½κΈ°). μ΄μ ClientResponse.__aexit__
μν΄ μλμΌλ‘ μνλλμ§ μμ΄ λ²λ Έμ΅λλ€. λΉ λ₯Έ μλμ λλ¦° μλ μ¬μ΄μλ μ νμ ν΅κ³Όνμ§ λͺ»νλ―λ‘ 'λλ¦Ό'μ΄ aiohttpκ° νμ λν μ°κ²°μ λ°ννκΈ°λ₯Ό κΈ°λ€λ¦¬κ³ μλ€κ³ μκ°ν©λλ€. @ fafhrd91 μμ΄λμ΄κ° μμ΅λκΉ?
@mal SSLκ³Ό λΉ SSLμ νμΈ νμ΅λκΉ? λ¬Έμ λ₯Ό μ’νλ λ° λμμ΄ λ κ²μ λλ€
SSL λ§ https://github.com/python/cpython/pull/2270 μΌλ‘ μλνλ €λ κ²½μ°
μ§μ°λμ΄ μ£μ‘ν©λλ€. μ§λμ£Όμ ν΄κ° μ€μ΄μμ΅λλ€. SSL λ λΉ SSLμ μλνμ§ μμμ§λ§ λ΄κ° μ¬μ©νλ ν μ€νΈ μΌμ΄μ€λ HTTPSκ° μλ μΌλ° HTTPμ λλ€. HTTPSμ μΆκ° μ€λ² ν€λλ‘ μ±λ₯μ΄ λ μ’μμ§ κ²μ΄λΌκ³ μμ¬ ν μ΄μ κ° μμ΅λκΉ?
κ·Έλ. κ·Έλ₯ httpsμΈμ§ νμΈνλ€κ³ μκ°νμ§ μμμ΅λλ€. κΈ°μ‘΄ λ¬Έμ λ‘λ§ μ€λͺ ν μ μμ΅λλ€.
μ¬λ¬λΆμ μλ‘μ΄ aiohttp 2.2.0 릴리μ€μ λν΄ ν μ€νΈ ν μ μμ΅λκΉ?
2.2.0
λ¬Έμ λ₯Ό μ¬μ©νμ¬ ν
μ€νΈ μΌμ΄μ€λ₯Ό λ€μ μ€ννκΈ° λ§νλ©΄λ©λλ€. π
κ·Έλ₯-μ€νμ λ€μ ν
μ€νΈ μΌμ΄μ€ μ λν 2.3.6
λ΄λΆ νκ³κ° μμλ€ 10,000μ μ΄ μκ°μ κ²°κ³Όλ₯Ό μ¬μ©νμ¬ λ¬Έμ λμ΄ μ΅μ μλͺ©μΌλ‘ π μ¬μ ν μ‘΄μ¬ ν¨μ νμΈν μ μμ΅λλ€ ~ 4 λ°° λλ¦° ( 20.13s
) μλμΌλ‘ ꡬν λ μΈλ§ν¬μ΄ μ κ·Ό λ°©μ ( 5.83
)보λ€.
@ aio-libs / aiohttp-committersμ μ무λ λ¨Όμ λ¬Έμ λ₯Ό ν΄κ²°νμ§ μμΌλ©΄ μκ°μ μ°ΎμΌλ €κ³ λ Έλ ₯ν κ²μ λλ€.
@dionhaefner κ° https://github.com/DHI-GRAS/itsybitsy/issues/1μμ μμ ν κ² κ°μ΅λλ€. μ¬κΈ°μ μ 보κ°μμ μ μμ΅λκΉ?
μ νν μμ λμ§ μμμ΅λλ€. limit
ν€μλ λμ μλ μ νμ μν΄ Semaphoreλ₯Ό μ¬μ©νκΈ° μν΄ @mal μ ν΄κ²° λ°©λ²μ μ¬μ©νμ΅λλ€.
sem = asyncio.Semaphore(max_connections)
connector = aiohttp.TCPConnector(limit=None)
session = aiohttp.ClientSession(connector=connector)
async def get_page(url):
async with sem:
async with session.get(url):
...
λλ₯Ό μν΄ μ μνν©λλ€.
@dteh μλ΅ μκ°μ΄ ν¬κ² λ€λ₯Ό μ μμΌλ―λ‘ google.comμ λν μ°κ²°μ ν μ€νΈ μΌμ΄μ€λ‘ μ¬μ©νκΈ°κ° μ΄λ ΅μ΅λλ€. λ‘컬 μλ²λ‘ λ€μ μλνλ κ²μ΄ μ’μ΅λλ€.
@mal μ λ @asvetlov κ° λΉ μΈλ§ν¬μ΄ κ²½μ°μ λν΄ μΈκΈνλλ‘ ν
asyncio.Semaphore
, asyncio.Queue
λ° aiohttp.BaseConnector.connect
ꡬνμ λμ μ°κ²° μλ₯Ό μ ννλ μμμ νμ©νλ λμΌν ν¨ν΄μ 곡μ νκ³ λ§€μ° λμΌν ꡬνμ κ°μ΅λλ€. κ·Έλμ:
1) aiohttp.BaseConnector.connect
μλ μ°κ²° μ νμ ꡬννλ λ²κ·Έκ° μμ΅λλ€.
2) .get
μ .connect
ν¨μ μ¬μ΄μ μ°κ²°μ΄ μ ν λ λ λνλλ λ²κ·Έκ° μμΌλ©° μΈλΆ μΈλ§ν¬μ΄λ₯Ό μ¬μ©νμ¬ ν΄κ²°λ©λλ€ (λ°°μμ μ²μμ λ§λ€μ΄μ§λλ€).
3) κΈ°ν.
@thehesiod λ΄κ° μ΄κ²μ λ³Έ μ§ limit
λ§€κ° λ³μκ° λ¬΄μμ μλ―Ένλμ§ μλ¬Έμ κ°μ§ κ²μ
λλ€. μλνλ©΄ (λ©λͺ¨λ¦¬μμ) μλ³ λ μ¬μ© μ¬λ‘λ₯Ό μ§μν κ²μ΄λΌλ μ€λͺ
μ΄ μκΈ° λλ¬Έμ
λλ€. κ·Έλ κ² μ€κ³λμ§ μμλ€λ©΄ κ³ λ €ν μμλ κΈ°λ₯μΌκΉμ?
λμκ²λμ΄ λ¬Έμ κ° μλνμ§λ§ μλ²½νμ§ μμ μμλ μ루μ λ°°ν¬λ₯Ό κ³ λ €ν λ§νΌ μΆ©λΆν μ°¨λ¨ λ κ² κ°μ΅λλ€. λλ κ·Έκ²μ΄ 1 λ λμ κ±°κΈ°μ μκ³ λ§μ λΆλ§μ΄ μμμ§λ§ ... aiohttpλ‘ νλ‘λμ μ μ€ννλ €λ μ¬λλ€μ μμν΄λ³΄μμμ€. κ·Έλ° λ¬Έμ λ‘ μΈν΄ ν μ μμ΅λλ€.
@asvetlov μ λμ΄ λ¬Έμ λ₯Ό λ€μ νμΈνκ³ νμΈν λ€μμ΄ μλ μΈλ§ν¬μ΄ λ©μ»€λμ¦μ μ μ§ κ΄λ¦¬λλ λͺ¨λ λ²μ μ aiohttpμ μ§μ μ μ© ν κ²μ μ μν©λλ€ (ν΄κ²°νλ κ°μ₯ μ’μ λ°©λ² μΈ κ² κ°μ΅λλ€). νμν κ²½μ° λμ€μ κ°μ / κ΅μ²΄ ν μ μμ΅λλ€. μ΄λ»κ² μκ°ν΄?
aiohttp λ²κ·Έκ°μλ κ²½μ° @pfreixesμ μ£ΌμμΌλ‘ - κ·Έκ²μ κ³ μ λμ΄μΌνλ€.
λ¨Όμ λ¬΄μ¨ μΌμ΄ μΌμ΄λκ³ μλμ§ μμ λ΄μΌν©λλ€.
@mal μ ν λ§€κ° λ³μλ μΌλ°μ μΌλ‘ μ΄λ€ μ νμ μλ ₯μ μ μ©νλ κ²μ΄ μλλΌ λμ μ°κ²° μλ₯Ό μ ννλ κ²μ λλ€. μ°Έκ³ λ‘ aiohttpλ₯Ό μ¬μ©νμ¬ μλ λμ μ¬λ¬ μλΉμ€μ κ±Έμ³ prod νκ²½μμ λ§€μΌ μλ°±λ§ κ±΄μ μμ²μ μμ±νμΌλ©° μμ μ ν λ° μΈλ§ν¬μ κ°μ κ²μ μ¬μ©νμ¬μ΄ λ¬Έμ κ° λ°μνμ§ μμμ΅λλ€.
λ¬Έμ κ° κΈ°λμ λ¬Έμ μΌκΉμ? μ΄κ²μ ν΅μ¬μ "μ΄κ²μ΄ λ²κ·Έμ λκΉ, μλλ©΄μ΄ μ¬μ© μ¬λ‘λ₯Ό μ§μνλ λ° μ¬μ©λλ λ€λ₯Έ λ°©λ²μ λκΉ?"μΈ κ² κ°μ΅λλ€. κ·Έλ¦¬κ³ μ무λ νμ€νμ§ μμ κ² κ°μ΅λλ€. μ§κΈ λΉμ₯μ μ¬μ©μμκ² λ²κ·Έμ²λΌ 보μ΄λ μμμΉ λͺ»ν νλμΌλ‘ μΈν΄ μ½κ°μ μ’μ κ°μμ λ¨μν λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ§ μλ κ²μ μ΄λ₯΄κΈ°κΉμ§ λ€μν μλ΅μ΄ λ°μνλ€κ³ μ£Όμ₯ν©λλ€.
@mal μ½λλ₯Ό λ μ½μ ν λ μ½λ κ²½λ‘λ₯Ό μΌλ§λ λΉμ·νκ² λ§λ€ μλμ§ κΉ¨λ«μ§ λͺ»νμ΅λλ€. λ κ²½μ° λͺ¨λ λμΌν μμ λ―Έν΄κ²° μμ
μ΄ μκ³ , ν κ²½μ°μλ μΈλ§ν¬μ΄μμ μ°¨λ¨ ν΄μ λ₯Ό κΈ°λ€λ¦¬κ³ μμ΅λλ€. TCPConnector
μ νμ λ€λ₯Έ. λΉ λ₯Έ μΌμ΄μ€κ° LIMITλ₯Ό μ¬μ©νλλ‘ λ λ€λ₯Έ λ³κ²½μ μννμ¬ λ μΌμ΄μ€κ° μ μ¬νκ³ aiohttpμ λ¬Έμ λ₯Ό κ°λ¦¬ν€λ λΉ λ₯Έ μΌμ΄μ€μ μ±λ₯μ μν₯μ λ―ΈμΉμ§ μμμ΅λλ€.
κ·Έλμ μ΄κ²μ λ€μ ν₯λ―Έ λ‘μ΅λλ€. μ±λ₯ μΆμ μ λ°λΌ selectors.py:select
λ©μλλ‘ μΈν΄ μμ
μ΄ λλ¦¬κ² μ€νλλ€λ κ²μ μκ³ μμΌλ―λ‘ (λΉ λ₯Έ μΆμ μ νμλμ§λ μμ) aiohttpκ° μ μνλλ‘ μ°κ²°μ μ°¨μ μΌλ‘ μ ννλ κ²μ²λΌ λ€λ¦½λλ€. λλ μ΄μ μ΄κ²μ΄ νμ€ν aiohttpμ μ±λ₯ λ¬Έμ λΌκ³ μκ°ν©λλ€. BaseConnectorμ μ¨μ΄ν° λ©μ»€λμ¦ λλ¬Έμ΄λΌκ³ μκ°ν©λλ€. μ²μμ LIMIT
μ°κ²°μ΄ μμ± λ λ€μ LIMIT * 99
κ° "λκΈ°μ"λ‘ λλλ κ²μ μμν μ μμ΅λλ€. μ΄κ²μ΄ κ°λ¨ν μΈλ§ν¬μ΄ λλ 쑰건μΌλ‘ λ체 λ μ μλμ§ κΆκΈν©λλ€.
κ·νμ μμ λν΄ κ°μ μ ν κ²μ λν΄ μ¬κ³Όλ립λλ€. μ΄ λ¬Έμ λ₯Ό μλ € μ£Όμ μ λ€μ ν λ² κ°μ¬λ립λλ€! λλ μ€λ μ΄κ²μ μ½κ° μ€ν ν μκ°μ΄μμ κ²μ΄λΌκ³ μκ°νμ§λ§ @asvetlov κ° μ΄κ²μ λ³λλ‘ μΆκ΅¬ ν μ μκΈ°λ₯Ό λ°λλλ€. λλ κΈ°κ³ μλ μλμ§λ§ μ΄ν΄ κ΄κ³μμ λλ€. :)
κ·Έλμ λ μ¬λ‘μ μλλ₯Ό ν¬κ² λμ΄λ PRμ λ§λ€μμ΅λλ€. μ΄κ²μ΄νλ μΌμ μμΈκ° μλ κ²½μ°μ μ¨μ΄ν° λͺ©λ‘μ ν΅ν΄ 리μ€ν μ νΌνλ κ²μ λλ€.
λ΄ μ»΄ν¨ν°μμλ λλ¦° κ²½μ° ~ 13 μ΄μμ 3 μ΄λ‘ λ³κ²½λμμ΅λλ€.
λꡬλ μ§ λ΄ PRμ κ²°κ³Όλ₯Ό νμΈνκ³ μΆμ΅λκΉ?
# 2937 λ° # 2964λ‘ μμ ν΄μΌν©λλ€.
μ΄ μ€λ λλ λ«ν ν μ΅κ·Ό νλμ΄ μμκΈ° λλ¬Έμ μλμΌλ‘ μ κ²Όμ΅λλ€. κ΄λ ¨ λ²κ·Έμ λν΄ [μ λ¬Έμ ]λ₯Όμ¬μμμ€.
μ΄ ν λ‘ μμ μ€μν μ μ΄ μλ€κ³ μκ°λλ©΄ [μ νΈ]μ ν΄λΉ μμΈ μ¬νμ ν¬ν¨νμμμ€.
κ°μ₯ μ μ©ν λκΈ
λ¬Έμ κ° κΈ°λμ λ¬Έμ μΌκΉμ? μ΄κ²μ ν΅μ¬μ "μ΄κ²μ΄ λ²κ·Έμ λκΉ, μλλ©΄μ΄ μ¬μ© μ¬λ‘λ₯Ό μ§μνλ λ° μ¬μ©λλ λ€λ₯Έ λ°©λ²μ λκΉ?"μΈ κ² κ°μ΅λλ€. κ·Έλ¦¬κ³ μ무λ νμ€νμ§ μμ κ² κ°μ΅λλ€. μ§κΈ λΉμ₯μ μ¬μ©μμκ² λ²κ·Έμ²λΌ 보μ΄λ μμμΉ λͺ»ν νλμΌλ‘ μΈν΄ μ½κ°μ μ’μ κ°μμ λ¨μν λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ§ μλ κ²μ μ΄λ₯΄κΈ°κΉμ§ λ€μν μλ΅μ΄ λ°μνλ€κ³ μ£Όμ₯ν©λλ€.