-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7a49be2
commit 25de9d9
Showing
2 changed files
with
290 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# Plus One | ||
|
||
You are given a **large integer** represented as an integer array `digits`, where each `digits[i]` is the `ith` digit of the integer. The digits are ordered from most significant to least significant in left-to-right order. The large integer does not contain any leading `0`'s. | ||
|
||
Increment the large integer by one and return the resulting array of digits. | ||
|
||
## Example 1: | ||
``` | ||
Input: digits = [1,2,3] | ||
Output: [1,2,4] | ||
Explanation: The array represents the integer 123. | ||
Incrementing by one gives 123 + 1 = 124. | ||
Thus, the result should be [1,2,4]. | ||
``` | ||
|
||
## Example 2: | ||
``` | ||
Input: digits = [4,3,2,1] | ||
Output: [4,3,2,2] | ||
Explanation: The array represents the integer 4321. | ||
Incrementing by one gives 4321 + 1 = 4322. | ||
Thus, the result should be [4,3,2,2]. | ||
``` | ||
|
||
## Example 3: | ||
``` | ||
Input: digits = [0] | ||
Output: [1] | ||
Explanation: The array represents the integer 0. | ||
Incrementing by one gives 0 + 1 = 1. | ||
Thus, the result should be [1]. | ||
``` | ||
|
||
## Example 4: | ||
``` | ||
Input: digits = [9] | ||
Output: [1,0] | ||
Explanation: The array represents the integer 9. | ||
Incrementing by one gives 9 + 1 = 10. | ||
Thus, the result should be [1,0]. | ||
``` | ||
|
||
## 풀이 | ||
```kotlin | ||
class Solution { | ||
fun plusOne(digits: IntArray): IntArray { | ||
var carry = 1 | ||
var index = digits.size - 1 | ||
var result: IntArray = digits | ||
|
||
while(index >= 0 && carry > 0) { | ||
result[index] = (result[index] + 1) % 10 | ||
carry = if(result[index] == 0) 1 else 0 | ||
|
||
index-- | ||
} | ||
|
||
if(carry > 0) { | ||
result = IntArray(digits.size + 1) | ||
result[0] = 1 | ||
} | ||
|
||
return result | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
# 코틀린 공식 가이드 2 | ||
|
||
## 취소(Cancellation) | ||
* 코루틴에서 실행되는 모든 중단 함수 (`suspending function`)들은 취소 요청에 응답 가능하도록 구현되어야 함. | ||
* 중단 함수는 실행 중 취소 가능한 구간마다 취소 요청이 있었는지 확인하고 요청이 있었다면 실행을 즉시 취소하도록 구현해야 함. | ||
* `kotlinx.coroutines` 라이브러리의 모든 중단함수는 이러한 취소 요청에 대응하도록 구현되어있음. | ||
* 취소를 지원하는 중단 함수들은 실행하는 동안 취소가 가능한 지점마다 현재 코루틴이 취소 되었는지 확인하며, 만약 취소되었다면 `CancellationException`을 발생시키며 종료함. | ||
|
||
> ReactiveX Observable을 구현해 본 경험이 있는 사람이라면 Observable의 코드 실행 중 취소 가능한 구간마다 isDisposed() 같은 취소 상태 확인 함수를 이용하여 현재 Observable의 구독 취소 여부를 확인하고 Observable의 데이터 방출을 정지하고 종료해야 하는지 판단해본 기억이 있을 것입니다. | ||
* 만약 다음과 같이 코루틴을 작성하면 취소 요청이 오더라도 작업을 멈추지 않고 계속 진행함 (`Sleep` 대신 `Busy-waiting` 구현을 해도 마찬가지) | ||
|
||
```kotlin | ||
fun main(args: Array<String>) = runBlocking { | ||
val job = launch(Dispatchers.Default) { | ||
for(i in 1..10) { | ||
println("I'm sleeping $i ...") | ||
Thread.sleep(500L) | ||
} | ||
} | ||
|
||
delay(1300L) | ||
println("main: I'm tired of waiting!") | ||
job.cancelAndJoin() | ||
println("main: Now I can quit.") | ||
} | ||
``` | ||
|
||
* 이 코루틴을 취소 요청에 친화적인 코드로 만들기 위해서는 취소가 가능한 시점마다 다른 `Continuation`에 실행 시간을 양보하는 `yield()` 함수를 호출하거나 | ||
* `CoroutineScope`에 정의된 `isActive` 속성을 참조하여 코루틴이 비활성 상태인 경우 작업을 중단하도록 하는 방법이 있음. | ||
|
||
### yield() 중단함수를 사용한 구현 | ||
|
||
```kotlin | ||
fun main(args: Array<String>) = runBlocking { | ||
val job = launch(Dispatchers.Default) { | ||
for(i in 1..10) { | ||
yield() | ||
println("I'm sleeping $i ...") | ||
Thread.sleep(500L) | ||
} | ||
} | ||
|
||
delay(1300L) | ||
println("main: I'm tired of waiting!") | ||
job.cancelAndJoin() | ||
println("main: Now I can quit.") | ||
} | ||
``` | ||
|
||
### isActive를 이용한 구현 | ||
|
||
```kotlin | ||
fun main(args: Array<String>) = runBlocking { | ||
val job = launch(Dispatchers.Default) { | ||
for(i in 1..10) { | ||
if(!isActive) { | ||
break | ||
} | ||
println("I'm sleeping $i ...") | ||
Thread.sleep(500L) | ||
} | ||
} | ||
|
||
delay(1300L) | ||
println("main: I'm tired of waiting!") | ||
job.cancelAndJoin() | ||
println("main: Now I can quit.") | ||
} | ||
``` | ||
|
||
* 취소가 가능한 중단함수들은 췻되면 `CancellationException`을 발생시킴 | ||
* 우리는 일반적인 예외처리 방식과 동일하게 이를 처리할 수 있음. | ||
* 만약 예외발생시 해제 해야할 리소스가 있다면 | ||
* `try~finally` 구문을 사용 | ||
* `use()` 함수를 사용 | ||
* 두 가지 방법으로 해결할 수 있음. | ||
|
||
### try ~ finally를 사용한 구현 | ||
```kotlin | ||
fun main(args: Array<String>) = runBlocking { | ||
val job = launch(Dispatchers.Default) { | ||
try { | ||
repeat(1000) { i-> | ||
println("I'm sleeping $i ...") | ||
delay(500L) | ||
} | ||
} finally { | ||
println("main : I'm running finally!") | ||
} | ||
} | ||
|
||
delay(1300L) | ||
println("main: I'm tired of waiting!") | ||
job.cancelAndJoin() | ||
println("main: Now I can quit.") | ||
} | ||
``` | ||
|
||
### use() 메소드를 이용한 구현 | ||
```kotlin | ||
fun main(args: Array<String>) = runBlocking { | ||
val job = launch { | ||
SleepingBed().use { | ||
it.sleep(1000) | ||
} | ||
} | ||
|
||
delay(1300L) | ||
println("main : I'm tired of waiting!") | ||
job.cancelAndJoin() | ||
println("main : Now I can quit.") | ||
} | ||
|
||
class SleepingBed : Closeable { | ||
|
||
suspend fun sleep(times: Int) { | ||
repeat(times) { i -> | ||
println("I'm sleeping $i ...") | ||
delay(500L) | ||
} | ||
} | ||
|
||
override fun close() { | ||
println("main : I'm running close() in SleepingBed!") | ||
} | ||
|
||
} | ||
``` | ||
|
||
## 취소 불가능한 코드 블럭의 실행 (Run non-cancellable block) | ||
* 이미 `CancellableException`이 발생한 코루틴의 `finally` 블록 안에서 중단 함수를 호출하면 현재 코루틴은 이미 취소된 상태이기 때문에 `CancellationException`이 발생함. | ||
* 보통 리소스를 정리하는 함수들은 논-블록킹으로 동작하기 때문에 이러한 제약이 큰 문제가 되지는 않음. | ||
* 이미 취소된 코루틴 안에서 동기적으로 어떤 중단 함수를 호출해야 하는 상황이라면 `withContext{ }` 코루틴 빌더에 `NonCanecllable` 컨텍스트를 전달하여 이를 처리할 수 있음. | ||
|
||
```kotlin | ||
fun main(args: Array<String>) = runBlocking { | ||
val job = launch { | ||
try { | ||
repeat(1000) { i -> | ||
println("I'm sleeping $i ...") | ||
delay(500L) | ||
} | ||
} finally { | ||
withContext(NonCancellable) { | ||
delay(1000) | ||
println("main : I'm running finally!") | ||
} | ||
} | ||
} | ||
|
||
delay(1300L) | ||
println("main : I'm tired of waiting!") | ||
job.cancelAndJoin() | ||
println("main : Now I can quit.") | ||
} | ||
``` | ||
|
||
|
||
## 타임아웃 (Timeout) | ||
* 일반적으로 어떤 코루틴의 실행을 중간에 취소해야 하는 경우는 그 수행시간이 너무 길어져 허용할 수 있는 시간을 넘어섰을 경우 | ||
* 이 경우 우리는 타임아웃을 지정하고 이 시간을 넘어설 경우 해당 작업을 취소하도록 구현할 수 있음. | ||
* 일반적으로 취소 요청이 없었음에도 어떤 코루틴의 실행을 중간에 취소해야 하는 경우는 그 코루틴의 수행시간이 허용 가능한 시간보다 길어졌을 경우. | ||
* 이러한 경우를 다루기 위해서 우리는 코루틴에 제한 시간 (`Timeout`)을 설정하고 이 시간이 넘어설 경우 코루틴을 취소되도록 구현할 수 있음. | ||
|
||
1. 제한 시간을 설정 할 대상이 되는 코루틴을 생성. | ||
2. 일정 시간 (Timeout) 지연 후 전달받은 `job`이 끝나지 않았으면 취소하는 동작을 하는 코루틴을 생성하고, 1번에서 만들고 실행한 코루틴의 `job` 객체를 전달함. | ||
3. 테스트를 위해 1번 코루틴은 2번 코루틴에서 설정한 시간보다 긴 수행시간을 갖도록 구현함. | ||
|
||
```kotlin | ||
fun main(args: Array<String>) = runBlocking<Unit> { | ||
val job = launch { | ||
try { | ||
repeat(1000) { i -> | ||
println("I'm sleeping $i ...") | ||
delay(500L) | ||
} | ||
} finally { | ||
println("main : I'm running finally!") | ||
} | ||
} | ||
|
||
launch { | ||
delay(1300L) | ||
println("main : I'm tired of waiting. Cancel the job!") | ||
if (job.isActive) { | ||
job.cancelAndJoin() | ||
} | ||
} | ||
} | ||
``` | ||
|
||
* 위 구현은 우리가 예상한대로 동작함. | ||
* 하지만 매번 Job 객체 참조를 유지하면서 별도의 코루틴에서 취소 하도록 하는 것은 번거롭기 때문에 이 경우 보통 `withTimeout()` 함수를 사용함. | ||
|
||
```kotlin | ||
fun main(args: Array<String>) = runBlocking<Unit> { | ||
withTimeout(1300L) { | ||
launch { | ||
try { | ||
repeat(1000) { i -> | ||
println("I'm sleeping $i ...") | ||
delay(500L) | ||
} | ||
} finally { | ||
println("main : I'm running finally") | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
* 위 함수를 실행하면 `TimeoutCancellationException`이 발생 | ||
* 이는 예제가 메인 함수에서 바로 실행되었기 때문. | ||
* 코루틴이 취소될 경우 발생하는 `CancellationException`은 코루틴에서 일반적인 종료 상항 중 하나로 간주됨. | ||
|
||
``` | ||
I’m sleeping 0 … | ||
I’m sleeping 1 … | ||
I’m sleeping 2 … | ||
main : I’m running finally! | ||
Exception in thread “main” kotlinx.coroutines.TimeoutCancellationException: Timed out waiting for 1300 ms at kotlinx.coroutines.TimeoutKt.TimeoutCancellationException(Timeout.kt:122) at kotlinx.coroutines.TimeoutCoroutine.run(Timeout.kt:88) | ||
Process finished with exit code 1 | ||
``` |