for
문의 주의점for
의 진행, 비진행 standard의 dynamic 변경을 눈치 채지 못한다.i=0; i<10; i++
for i in range(10): # for(int i=0 ; i<10 ; i++)
print(i) # i=0, 1, 2, 3, 4, 5, 6, 7, 8, 9
for i in range(0,10):
print(i)
i=5; i<10; i++
for i in range(5, 10): # for(i=5 ; i< 10; i++)
print(i) # i=5, 6, 7, 8, 9
i=10, i>0; i--
for i in range(10, 0, -1):
print(i)
--- 출력 ---
10
9
8
7
6
5
4
3
2
1
for idx,val in enumerate( )
arr=[1,2,3,4,5]
for idx,val in enumerate(arr):
print(idx, val)
for
문에서 반복문 때, 위처럼 in range
를 사용한다. 하지만, range(0,100)
과 같은 경우 100 size의 list
를 만든다. 이는 분명 의미 없는 메모리 낭비 이다.Generator
를 사용하자.# 1.
def gen_func(nums):
for i in nums:
yield i * i
for i in gen_func([1,2,3,4,5]):
print(i)
-----
# 2.
gen_list = (x*x for x in [1,2,3,4,5]) # not [x*x for x in [1,2,3,4,5]]
for i in gen_list:
print(i)
# 1.
def gen_func(nums):
for i in nums:
yield i * i
arr = [1,2,3,4,5]
for i in gen_func(arr):
print(i)
-------
# 2.
arr = [1,2,3,4,5]
gen_list = (x*x for x in arr)
for i in gen_list:
print(i)
-------
# 3.
arr = (x for x in range(100))
print(arr) ==> generator<0x100000>
next(arr) ====> 0
a = []
print(a) # false
i =0
while True:
if not a:
break
print(a[i])
i+=1
yield
로 main과 subroutine이 왔다갔다.None
반환send()
를 사용해 main 루틴에서 yield 로 전달 가능GEN_CREATED
: 처음 대기 상태GEN_RUNNING
: 실행 상태GEN_SUSPENDED
: yield
대기 상태GEN_CLOSED
: 실행 완료 상태>=3.5
$ python3 -m pip install asyncio
$ python3 -m pip install beautifulsoup4
asyncio
: async, await의 syntax를 사용한 비동기 IO를 위한 libraryasyncio
await (= yield) 'Non-block 하고픈 함수 사용'
import asyncio
from urllib.request import urlopen
from concurrent.futures import ThreadPoolExecutor
import threading
urls = ['https://naver.com', 'http://daum.net']
async def fetch(url, executor):
# 스레드명 출력
print('Thread Name : ', threading.current_thread().getName(), 'Start', url)
# 실행
res = await loop.run_in_executor(executor, urlopen, url) # loop는 main에서 선언했기때문에 참조할 수 있다.
print('Thread Name : ', threading.current_thread().getName(), 'Done', url)
# 결과 반환
return res.read()
async def main():
# async: 나는 비 동기 함수야!
# 스레드 풀 생성
executor = ThreadPoolExecutor(max_workers=10)
# future 객체 모아서 gather에서 실행
futures = [
asyncio.ensure_future(fetch(url,executor)) for url in urls # 실행할 함수를 쌍으로 넣으면된다. # 각 사이트에 각 스레드가 실행된다.
]
# 결과 취함
res = await asyncio.gather(*futures) # futures가 끝날때까지 기다린다. (*는 그냥 unpacking)
print('Result : ', res)
if __name__ == '__main__':
loop = asyncio.get_event_loop() # 루프 초기화
loop.run_until_complete(main()) # 작업완료까지 대기. 끝날 때 까지 이 루프는 계속된다.
$ pip3 install beautifulsoup4
from bs4 import Beautifulsoup4
getpage(x)
마다 동기 및 blocking 함수 이기 때문에, 5초 소요1.0x
초 소요#!/usr/bin/env python3
import time
import asyncio
async def getpage(url):
s=time.time()
await asyncio.sleep(1) # Bg 대기
print('%d' % (url))
e=time.time()
print(e-s)
async def main():
await asyncio.gather(
getpage(1),
getpage(2),
getpage(3),
getpage(4),
getpage(5)
)
loop=asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
$ pip3 install requests
0.94
초 소요0.21
초 소요#!/usr/bin/env python3
import requests
import asyncio
import time
async def getpage(url):
req=await loop.run_in_executor(None, requests.get, url)
html=req.text
print(len(html))
async def main():
await asyncio.gather(
getpage("https://www.naver.com"),
getpage("https://www.naver.com"),
getpage("https://www.naver.com"),
getpage("https://www.naver.com"),
getpage("https://www.naver.com")
)
s=time.time()
loop=asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
e=time.time()
print(e-s)
import asyncio
async def run(cmd):
proc = await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
print(f'[{cmd!r} exited with {proc.returncode}]')
if stdout:
print(f'[stdout]\n{stdout.decode()}')
if stderr:
print(f'[stderr]\n{stderr.decode()}')
if __name__ == '__main__':
asyncio.run(run('echo helloworld'))
# === 출력 ===
['echo helloworld' exited with 0]
[stdout]
helloworld
asyncio
서브프로세스 함수는 비동기 이고, asyncio
가 이러한 함수로 작업 할 수 있는 많은 도구를 제공한다.import asyncio
async def run(cmd):
proc = await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
print(f'[{cmd!r} exited with {proc.returncode}]')
if stdout:
print(f'[stdout]\n{stdout.decode()}')
if stderr:
print(f'[stderr]\n{stderr.decode()}')
async def async_main():
await asyncio.gather(
run('ls'),
run('sleep 1; echo "hello"')
)
if __name__ == '__main__':
asyncio.run(async_main())
coroutine asyncio.create_subprocess_exec(program, *args, stdin=None, stdout=None, stderr=None, limit=None, **kwds)
주의 Deprecated since version 3.8, removed in version 3.10: The loop
parameter.
coroutine
asyncio.
create_subprocess_shell
(cmd, stdin=None, stdout=None, stderr=None, limit=None, **kwds
)
argument | description |
---|---|
cmd | 셸 명령을 실행한다. |
limit | Process.stdout 과 Process.stderr 에 대한 StreamReader 래퍼의 버퍼 한계 설정 |
return | description |
---|---|
Process 인스턴스 | 성공 |
>= 3.2
multiprocess
, CPython
from concurrent import futures
#!/usr/bin/env python3
from concurrent import futures
WORK_LIST = [10**3, 10**4, 10**5]
def sum_gen(n):
return sum(n for n in range(1, n+1))
if __name__ == '__main__':
with futures.ThreadPoolExecutor() as executor:
result = executor.map(sum_gen, WORK_LIST)
print(*result)
#!/usr/bin/env python3
from concurrent import futures
WORK_LIST = [10**3, 10**4, 10**5]
def sum_gen(n):
return sum(n for n in range(1, n+1))
if __name__ == '__main__':
futures_list = []
with futures.ThreadPoolExecutor() as executor:
for work in WORK_LIST:
future = executor.submit(sum_gen, work)
futures_list.append(future)
print('Scheduling for {} : {}'.format(work,future))
#!/usr/bin/env python3
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, wait, as_completed
WORK_LIST = [10**7, 10**4, 10**5]
def sum_gen(n):
return sum(n for n in range(1, n+1))
if __name__ == '__main__':
futures_list = []
with ThreadPoolExecutor() as executor:
for work in WORK_LIST:
future = executor.submit(sum_gen, work)
futures_list.append(future)
print('Scheduling for {} : {}'.format(work,future))
result = wait(futures_list, timeout=0.00000001)
print('Completed Tasks: ' + str(result.done))
print('Completed Tasks: ' + str(result.not_done))