3월, 2020의 게시물 표시

2020.03.16 Multiprocessing의 map_async, apply등 나머지

Multiprocessing에서 map 함수의 불편한 점은 2개 이상의 인자를 취하는 함수를 사용할 수 없다는 것이다. 예를 들어 pool.map(func, [(10, 20)])을 하면 func의 첫번째 인자로 10, 두번째 인자로 20이 들어가기를 기대하지만 막상 실행해보면 그냥 첫번째 인자에 (10, 20) 튜플이 들어가게 된다. 이 땐 multi-argument를 accept 하는 함수로 starmap을 사용할 수 있다. map_async callback과 error_callback을 인자로 받을 수 있다. Non-block 방식이기 때문에 프로세스에게 일감을 부여하고 바로 다시 메인 쓰레드로 제어권이 돌아온다. 제어권이 돌아오고 다른 프로세스들은 job을 열심히 돌릴텐데, 이 때 job의 결과물이 모두 반환되면 실행할 callback을 정의할 수 있다. 각 프로세스별로 실행한 함수의 return값을 모두 모아서 callback의 인자로 넘겨준다. 따라서 callback을 정의하여 어디에 notify를 해주던가, 알려주던가 하는 방법이 있다. 완료 되었을 때 callback을 넘겨줄 수 있기 떄문에 후처리를 해줄 수 있다. 이를 확인할 수 있는 함수는 get, wait, ready, successful     def callback(res):         print(res)     pool = multiprocessing.Pool()                       # 현재 PC의 CPU 코어가 12개이다.     a = pool.map_async(calc, range(21, 26), callback=callback)     print(a.ready())     print('Blo...

2020.03.06 EC2에서 계산작업을 돌리는데 속도가 매우 느리다면?

최근에 ec2에서 계산 작업 돌릴 일이 있어 사이즈가 있었다. AWS RDS + AWS EC2를 사용하고 사이즈는 둘 다 거의 최소 사이즈였다. EC2에서 명령어를 실행하면 실시간으로 콘솔에 로깅을 하면서 실시간으로 작업 현황을 보여주도록 해놨는데 어떨 때는 잘 되다가 또 어떨때는 엄청나게 느려지는 경우가 있었다. 어제는 실행을 시켰더니 속도가 매우매우 느렸었는데 원인은 swap 메모리 사용이었다. RDS의 메모리 사이즈가 작아서 내가 불러오려는 쿼리의 총 메모리 용량보다 작았고 그로 인해 SWAP 메모리를 20메가 이상으로 사용한 흔적이 있었다. 이 때 RDS의 사이즈를 늘려주는것도 방법이지만, 그게 여의치 않을 때는 쿼리를 수정해야한다. SQLALCHEMY를 사용한다는 가정하에, 쿼리 수정은 아래와 같은 방법으로 할 수있다. 먼저 query를 호출하면 .all()을 호출하던 그렇지 않던 메모리에 한꺼번에 result set을 올려두는 듯하다. 그러면 당연히 메모리를 많이 차지하는데 어차피 한번에 계산을 하지도 못하기 때문에 필요한만큼만 불러와서 사용할 수 있도록 한다. 간단한 방법은 Query.yield_per() API를 사용하는 것. yield_per()의 인자로 받는 integer가 한번에 불러올 레코드의 갯수다. 총 레코드가 10만개였는데 만약 yield_per(1000)로 1000개씩만 불러오면 당연히 메모리 사용량은 감소할 것이다. 단 yield_per()를 사용할때는 주의할 점이 있다. eager_loading이 된 object들은 yield_per()를 사용할 수 없다. 따라서 joinedload 옵션을 사용하는 쿼리는 바로 사용할 수가 없고,  selectinload로 변경해서 사용해야 yield_per()를 사용할 수 있다고 한다. 왜인지는 좀 더 찾아봐야 하고 일단은 메모만 해놓는다.