[Lecture] Kotlin 문법 종합반 KDT 실무형 Android 앱개발자 1회차 (5주차)_Part 2

Minjun Kim·2023년 7월 21일
0
post-thumbnail

확장함수

클래스를 수정하지 않고 메소드를 추가할 수 있다.

  • 코틀린은 자바와 달리 외부에서 클래스의 메소드를 추가 가능

  • 원하는 메소드가 있지만 내가 설계한 클래스가 아닐 때 외부에서 메소드를 관리함

  • 내 목적을 위해 외부에서 관리하기 때문에 원본 클래스의 일관성을 유지 가능

  fun main() {		// fun 클래스명.메소드명 = 실행 코드
      fun Student.getGrade() = println("학생의 등급은 ${this.grade} 입니다")
      var student = Student("참새", 10, "A+")
      student.displayInfo()
      student.getGrade()
  }

  class Student(name: String, age: Int, grade: String) {
      var name: String
      var age: Int
      var grade: String

      init {
          this.name = name
          this.age = age
          this.grade = grade
      }

      fun displayInfo() {
          println("이름은 ${name} 입니다")
          println("나이는 ${age} 입니다")
      }
  }

비동기 프로그래밍

여러가지의 로직들이 완료 여부에 관계없이 실행되는 방식을 의미

  • 순서대로 하나의 작업씩 수행하는 행위를 동기적 프로그래밍 이라 한다.
  • 순차적으로 수행하기 때문에 앞선 작업에 영향을 받는다.
    -> 만약 앞의 작업이 끝나지 않는다면 뒷 작업은 영원히 수행되지 않는다.

정리

  • 동기 프로그래밍 : 결과값이 리턴될 때까지 모든 작업 stop
  • 비동기 프로그래밍 : 결과값에 관계없이 다음 작업 수행
  • 동기는 한 가지씩 작업을 처리하고 비동기는 다양한 일을 동시에 수행

스레드

로직을 동시에 실행할 수 있도록 도와주는 개념

  • 프로그램은 하나의 메인 쓰레드(실행흐름)가 존재한다.

  • 하나의 메인 쓰레드는 fun main(), 메인함수를 의미한다.

  • 별도의 자식 쓰레드를 생성해서 동시에 로직을 실행할 수 있다.

  • 코틀린은 thread 키워드를 사용

쓰레드를 사용하는 이유

  • 몬스터를 공격하고, 체력이 줄어들고, 효과음이 동시에 발생해야 함

  • 경마 프로그램의 말들은 동시에 출발해야 함


코루틴

  • 쓰레드보다 더욱 경량화된 동시 처리 기능을 제공

  • 최적화된 비동기 함수를 사용

  • 하드웨어 자원의 효율적인 할당을 가능하게 한다.

  • 안정적인 동시성, 비동기 프로그래밍을 가능하게 한다.

  • 로직들을 협동해서 실행하자는 것이 목표이고 구글에서 적극 권장

빌더

  • 코루틴은 빌더 와 함께 사용한다.

  • 빌더의 종류
    일반적으로 launchasync 빌더를 가장 많이 사용한다.

launch

  • 결과값이 없는 코루틴 빌더를 의미한다.

  • Job객체로 코루틴을 관리

  • Job객체의 함수:
    join : 현재의 코루틴이 종료되기를 기다림
    cancel : 현재의 코루틴을 즉시 종료함

async

  • 결과값이 있는 코루틴이고 Deffered 타입으로 값을 리턴해준다.


스코프 범위

  • 코루틴은 스코프로 범위를 지정할 수 있다.

GlobalScope

- 앱이 실행된 이후에 계속 수행되어야할 때 사용

CoroutineScope

- 필요할 때만 생성하고 사용 후에 정리가 필요


Dispatcher

  • 코루틴을 실행할 쓰레드를 Dispatcher 로 지정할 수 있다.

Dispatchers.Main

- UI와 상호작용하기 위한 메인쓰레드

Dispatchers.IO

- 네트워크나 디스크 I/O작업에 최적화되어있는 쓰레드

Dispatchers.Default

- 기본적으로 CPU최적화되어있는 쓰레드
  • 안드로이드에서는 특히 Dispatcher 간의 변환 을 해야하는 작업을 고려해야 함 (withContext)
    ex) IO에서 작업 처리했는데 결과값을 Main에서 보고 싶을 때
  • 코틀린에서 코루틴을 사용하기 위해서는 외부 라이브러리를 추가해줘야 함
실습
JVM환경에서는 main이 종료되기 때문에 코루틴의 결과를 확인할 수 없음
-> job의 join 메소드로 해결

fun main(args: Array<String>) {
    println("메인쓰레드 시작")
    var job = GlobalScope.launch {
        delay(3000)
        println("여기는 코루틴...")
    }
    runBlocking {
        job.join()
    }
    println("메인쓰레드 종료")
}


다른 코루틴 스코프를 사용했을 경우

fun main(args: Array<String>) {
    println("메인쓰레드 시작")
    var job = CoroutineScope(Dispatchers.Default).launch {
        delay(3000)
        println("여기는 코루틴...")
    }
    runBlocking {
        job.join()
    }
    println("메인쓰레드 종료")
		job.cancel()
}


여러 개의 코루틴을 사용할 수 있음
- 코루틴의 결과값을 리턴 받을 수 있음
- 결과값을 리턴 받아야하기 때문에 await은 일시 중단이 가능한 코루틴에서 실행가능함

fun main(args: Array<String>) {
    println("메인쓰레드 시작")
    var job = CoroutineScope(Dispatchers.Default).launch {
        var fileDownloadCoroutine = async(Dispatchers.IO) {
            delay(10000)
            "파일 다운로드 완료"
        }
        var databaseConnectCoroutine = async(Dispatchers.IO) {
            delay(5000)
            "데이터베이스 연결 완료"
        }
        println("${fileDownloadCoroutine.await()}")
        println("${databaseConnectCoroutine.await()}")
    }
    runBlocking {
        job.join()
    }
    println("메인쓰레드 종료")
    job.cancel()
}

쓰레드와 코루틴 정리

  • 둘 다 동시성 프로그래밍 을 위한 기술

  • 동시성 프로그래밍 기술은 Context Switching 이 중요한 개념

쓰레드

- 최소 작업 단위: Thread

- 각 thread가 독립적인 Stack 메모리 영역을 가진다.
- 동시성 보장 수단 : Context Switching

- 운영체제 커널에 의한 context Switching을 통해 동시성을 보장

- 블로킹 (Blocking)

  - Thread A가 Thread B의 결과를 기다리고 있음
  
  - 이 때, Thread A는 블로킹 상태
  
  - A는 Thread B의 결과가 나올 때까지 해당 자원을 사용하지 못 함

  • Thread A가 Task 1을 수행하는 동안 Task 2 의 결과가 필요하면 Thread B를 호출해요
  • 이때 Thread A는 블로킹 되고 Thread B로 프로세스간에 스위칭이 일어나 Task 2을 수행해요
  • Task 2가 완료되면 Thead A로 다시 스위칭해서 결과 값을 Task 1에게 반환해요
  • 이때 Task 3, Task 4는 A, B작업이 진행되는 도중에 멈추지 않고 각각 동시에 실행되게 되요
  • 이때 컴퓨터 운영체제 입장에서는 각 Task를 쪼개서 얼마나 수행할지가 중요하겠죠?
  • 그래서 어떤 쓰레드를 먼저 실행해야할지 결정하는행위를 스케쥴링이라고 해요
  • 이러한 행위를 통해 동시성을 보장해요


코루틴

- 최소 작업 단위 : Coroutine Object

- 여러 작업 각각에 Object를 할당

- Coroutine Object도 엄연한 객체이기 때문에 JVM Heap에 적재함 (코틀린 기준)
- 동시성 보장 수단 : Programmer Switching (No-Context Switching)

- 소스 코드를 통해 Switching 시점을 마음대로 정함 (OS는 관여하지 않음)

- Suspend (Non-Blocking)

  - bject 1이 Object 2의 결과를 기다릴 때 Object 1의 상태는 Suspend로 변경된다.
  
  - 그래도 Object 1을 수행하던 Thread는 그대로 유효함
  
  - 그래서 Object 2도 Object 1과 동일한 Thread에서 실행된다.

  • Coroutine은 작업 단위가 Object라고 했어요
  • Task 1을 수행하다가 Task 2의 수행요청이 발생했다고 가정해볼게요
  • 신기하게도 컨텍스트 스위칭 없이 동일한 Thread A에서 수행할 수 있어요
  • Thread C처럼 하나의 쓰레드에서 여러 Task Object들을 동시에 수행할 수 있어요
  • 이러한 특징때문에 코루틴을 Light-Weight Thread 라고 이야기해요

요약

  • 쓰레드나 코루틴은 각자의 방법으로 동시성을 보장하는 기술

  • 코루틴은 Thread를 대체하는 기술이 아님 -> 하나의 Thread를 더욱 잘개 쪼개서 사용하는 기술

  • 코루틴은 쓰레드보다 CPU 자원을 절약하기 때문에 Light-Weight Thread 라고 한다.

  • 구글에서는 코틀린의 코루틴 사용을 적극 권장하고 있음

profile
응애 나 아기 뉴비

0개의 댓글