-
Future 의 concurrency controlscala/basic 2021. 3. 28. 15:52
playframework 에서 1,000 개의 DB item 을 빠르게 조회할 필요가 있었다.
play-ws 를 사용하면 Http Api 호출을 async action 으로 처리할 수 있다.
그런데 1,000 번의 Http Api 호출을 순식간에 진행해 DB 에 무리가 갈 수 있다.
오히려 성능을 제한해 한번에 100 건씩 호출해 10 번에 나누어서 처리하고 싶다.
아래 글을 참고해 코딩해 봤다.
stackoverflow.com/questions/49924941/how-to-control-the-concurrency-of-future-sequence-in-scala
/** * list 의 element 를 n 개 단위로 f 를 적용해 처리함 (n 개가 모두 처리되어야 다음 n 개를 처리함) * fast fail 이 되지 않도록 할려면 f 에서 Future.failed 이 발생되어서는 안된다. * * @param list 처리 대상 element 가 들어있는 list * @param n 한번에 n 개씩 처리함 * @param f 각각의 element 에 적용할 function * @param ec ExecutionContext * @return element 의 하나라도 Future.failed 이 발생하면 전체 리턴은 Future.failed 됨에 주의 */ def batchParN[A, B](list: List[A])(n: Int)(f: A => Future[B])(implicit ec: ExecutionContext): Future[List[B]] = { def op(acc: Future[List[B]], group: List[A]): Future[List[B]] = for { a <- acc b <- Future.traverse(group)(x => f(x)) } yield a ++ b list.grouped(n).foldLeft(Future.successful(List.empty[B]))(op) }
위의 방법으로는 99개가 1초만에 처리되고 1개가 아직 처리 되지 않았다면, 처리되지 않은 1개가 처리될 때까지 기다려 완료되어야만 다음 100개를 처리하게 된다. 좀 더 리소스를 효율적으로 사용하고 싶다면, ZIO 의 ZIO.foreachParN 을 사용하는 것도 좋을 것 같다.
'scala > basic' 카테고리의 다른 글
Pattern Match 조합 - Email 주소 예제 (0) 2021.07.27 enum 을 사용한 모델링 (0) 2021.07.23 typeclass 는 언제 사용하면 좋을까? (0) 2021.06.09 Dark Syntax Sugar (0) 2021.05.23 Scala Learning (0) 2021.03.28