티스토리 뷰

Language/Kotlin

Kotlin. Coroutine Basic.

out of coding 2020. 7. 4. 01:16

코루틴은 코틀린에만 있는 개념은 아닙니다. 여러 언어에 있는 개념이지만 일단은 Kotlin 입니다.

Coroutine은 협력형 multitasking을 이용하여 동시성 프로그래밍을 지원하고 해당 루틴을 suspended하는 방식으로 context-switching을 없애고 최적화된 비동기 함수를 통해 비선점형으로 작동하기 때문에 복잡한 nonblocking code를 간결하게 해주며 더 나은 성능을 지원합니다.

 

https://www.youtube.com/watch?v=_hfBv0a09Jc&feature=youtu.be&t=10m12s

아주 기본적인 부분들만 이야기 합니다.

launch, async

Coroutine에서 사용되는 함수는 suspend로 선언된 지연 function 이어야 합니다.

컴파일러가 suspend가 붙은 function을 자동적으로 추출하여서 분리된 routine을 만들어 냅니다.

suspend 키워드는 사용자 함수에도 사용이 가능하지만 coroutine 외에서 사용하면 error가 발생하게 됩니다.

launch에 suspend를 사용하기

suspend fun func1() : String {
  delay(2000)
  return "Work1"
}

suspend fun func2() : String {
  delay(3000)
  return "Work2"
}

private fun launchFunction() {
  GlobalScope.launch {
    // 순차적으로 실행됩니다.
    val one = func1()
    val two = func2()
  }
    
  // 이리로 바로 진행됩니다.
}

async coroutine builder

async로 만들어진 부분은 Deferred하게 만들어지고 이것을 await을 통해서 값을 받을수 있게 됩니다.

private fun worksInParallel() {
  val threadPool = Executors.newFixedThreadPool(4)
  val MyContext = threadPool.asCoroutineDispatcher()

  // Deferred<T> 를 통해 결과값을 반환한다.
  val one = GlobalScope.async(MyContext) {
    func1()
  }
    
  val two = GlobalScope.async {
    func2()
  }

  GlobalScope.launch {
    val combined = one.await() + "_" + two.await()
    println("Kotlin Combined : $combined")
  }
}

자바로 따지면 async는 CompletableFuture.supplyAsync(), Deferred는 Future와 같은 기능입니다.

runBlocking

새로운 Coroution을 run하고 완료되기 전까지 현재 스레드를 block하게 됩니다.

어떤 의미냐면 function에서 만들어져서 사용을 하게 된다면 해당 부분을 바로 return 하지 않고 동작이 완료되고 나서 return하게 됩니다.

@GetMapping
fun index() : ResponseEntity<String> {
  val sum = runFunction()
  return ResponseEntity.ok("Hello world : $sum, ${System.currentTimeMillis()}")
}

fun runFunction() = runBlocking {
  var sum = 0
  for (number in 0..Int.MAX_VALUE) {
    sum += number
  }

  sum
}

예를 들기 위해서 이렇게 만들었는데. suspendMethod에서 sum을 반환하게 됩니다.

다른 동작이 들어오기는 하지만 이 동작은 별도로 동작하게 됩니다.

join, cancel

명시적으로 coroutine 작업이 완료되는 것을 기다릴때는 join()을 취소할때는 cancel() 함수를 이용 합니다.

fun main() = runBlocking<Unit> {
  val job = launch {
    delay(1000L)
    println("World!")
  }
  
  println("Hello")
  job.join()
  job.cancel()
}

대량의 coroutine

repeat(100_000) {
  launch {
    delay(1000L)
    print("Hello!")
  }
}

이런식으로 대량으로 만들수 있다고 합니다. 스레드로 저런걸 만들면 상상하는 일이 일어납니다. Out of Memory

Sequence, yield

// 피보나치 수열 생성
val fibonacciSeq = sequence {
  var before = 0
  var now = 1
  yield(1)

  while (true) {
    val next = before + now
    yield(next)
    before = now
    now = next
  }
}

fun test() {
    println(fibonacciSeq.take(8).toList())
    // 8개를 출력하도록 만들고 1, 1, 2, 3, 5, 8, 13, 21
}

yield는 실행을 잠시 멈추고 요소를 반환하고 멈춘 시점에서 다시 실행한다고 합니다.

즉 반환할 값을 넣어주게 되면 반환이 되고 다시 재개됩니다.

yield, yieldAll, yieldyield(value), yieldAll(list), yieldAll(sequence) 를 사용 가능합니다.

백엔드 단위에서는 잘 쓸거 같지는 않아요.

'Language > Kotlin' 카테고리의 다른 글

파일 끝에 개행을 추가해야 하는 이유  (0) 2022.12.08
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함