오늘도 더 나은 코드를 작성하였습니까?

flow의 실행 방법 본문

Coroutine/coroutineFlow

flow의 실행 방법

hik14 2021. 5. 31. 11:29

Flow가 요청 시 값을 생성하거나 지연 생성하는 방법을 알아보기 위해 각 항목이 생성되기 전과 도중 그리고 이후에 (1, 2, 3) 값을 내보내기.

 

fun makeFlow() = flow {
   println("sending first value")
   emit(1)
   println("first value collected, sending another value")
   emit(2)
   println("second value collected, sending a third value")
   emit(3)
   println("done")
}

scope.launch {
   makeFlow().collect { value ->
       println("got $value")
   }
   println("flow is completed")
}

collect 람다와 flow 빌더를 오가며 실행되는 방식을 확인할 수 있습니다.

flow 빌더는 emit을 호출하면 항상 요소가 완전히 처리될 때까지 suspends 상태가 됩니다.

그런 다음, flow에서 다른 값이 요청되면 다시 내보내기를 호출할 때까지 정지했던 위치에서 resumes 처리됩니다.

 

flow 빌더가 완료되면 Flow가 취소되고 collect가 다시 시작되어 호출 코루틴에서 'flow 완료'가 출력됩니다.

 

collect 호출은 매우 중요합니다. Flow는 Iterator interface를 노출하는 대신 collect와 같은 일시 중단 연산자를 사용하므로 언제 active consume(소비)되는지 항상 알 수 있습니다.

 

더 중요한 것은 호출한 곳에서  리소스를 정리할 수 있도록 더 이상 값을 요청할 수없는시기를 알수 있다. 

println("flow is completed")

 

* Flow는 코루틴을 사용하여 처음부터 빌드됩니다.

코루틴의 suspend  resume 메커니즘을 사용하면 생산자(flow)와 소비자(collect)의 실행을 동기화할 수 있습니다.

반응형 스트림을 사용한 적이 있고 백 프레셔의 개념을 잘 알고 있다면 코루틴을 정지하여 Flow에서 구현된다는 점을 이해할 것입니다.

 

flow  실행 시점

 Flow는 collect 연산자가 실행되면 실행이 시작됩니다. flow 빌더 또는 다른 API를 호출하여 새로운 Flow를 만들어도 아무 작업이 실행되지 않습니다. suspend 연산자 collect는 Flow에서 터미널 연산자라고 합니다.

 kotlinx-coroutines에서 제공되는 toList,  first,  single 같은 다른 정지 터미널 연산자가 있으며, 고유하게 빌드할 수도 있습니다.

 

Flow가 실행되는 시점:

  • 터미널 연산자가 적용될 때마다(새로운 각 호출이 이전에 시작된 호출과 상관없이 독립적임) 실행
  • 포함하는 코루틴이 취소될 때까지 실행(flow의 터미널 연산자를 호출한 scope가 종료되면 종료된다.)
  • 마지막 값이 완전히 처리되고 다른 값이 요청되었을 때

이러한 규칙은 Flow의 기본 동작입니다.

이전 실행과의 동일한 상태를 공유할 수 있게 하여, 모든 터미널연산자에 대해 실행을 재개 하지않음. 

flow의 기본 제공 또는 사용자 커스텀을 통하여 collecting을 독립적으로 실행한다.

 

flow을 실행하는 것을 flow collecting이라고합니다.

myFlow.toList () // toList는이 흐름을 수집하고 값을 List에 추가합니다.

collect를 통해서 Flow에서 개별 값을 수집가능하다.

myFlow.collect {항목-> println ( "$ 항목이 수집되었습니다")}

 

Flow는 구조화 된 동시성에 참여할 수 있으며 Flow에서 장기 실행 코 루틴을 시작하는 것이 안전합니다.

caller가 취소 될 때 항상 코루틴 협력 취소 규칙을 사용하여 정리되기 때문에 Flow가 리소스를 누출 할 가능성이 없습니다.

 

fun makeFlow() = flow {
   println("sending first value")
   emit(1)
   println("first value collected, sending another value")
   emit(2)
   println("second value collected, sending a third value")
   emit(3)
   println("done")
}

scope.launch {
   val repeatableFlow = makeFlow().take(2)  // we only care about the first two elements
   println("first collection")
   repeatableFlow.collect()
   println("collecting again")
   repeatableFlow.collect()
   println("second collection completed")
}

flow 람다는 collect가 호출 될 때마다 맨 위에서 시작됩니다.

flow이 네트워크 요청과 같은 값 비싼 작업을 수행 한 경우 중요합니다. 또한 take (2) 연산자를 적용 했으므로 flow은 두 개의 값만 생성합니다. 두 번째 방출 호출 후 흐름 람다를 다시 재개하지 않으므로 "second value collect ..."줄은 인쇄되지 않습니다.