본문 바로가기

프로그래밍/SWIFT

[Swift] 가장 간단한 Actor 샘플코드, Actor Counter

반응형

swift concurrency 에 actor 라는 개념이 있다. 가장 간단하게 actor 를 사용하는 예제를 만들어 보았다. ( with a little help of gpt )

횟수를 카운트 하는 매우 간단한 카운터 class/actor이다. 카운터를 생성해서, 동시에 수행되는 두 태스크에서 동시에 카운팅이 이루어진다.

import Foundation

actor MyActorCounter {
    var counter = 0

    func incrementCounter() {
        counter += 1
    }
}

class MyClassCounter {
    var counter = 0

    func incrementCounter() {
        counter += 1
    }
}

func testActorCounter() async -> Void {
    let counter = MyActorCounter()

    await Task {
        let task1 = Task {
            for _ in 0 ..< 10000 {
                await counter.incrementCounter()
            }
        }

        let task2 = Task {
            for _ in 0 ..< 10000 {
                await counter.incrementCounter()
            }
        }

        await task1.result
        await task2.result

    }.result

    print("actor counter count :", await counter.counter)
}

func testClassCounter() async -> Void {
    let counter = MyClassCounter()

    await Task {
        let task1 = Task {
            for _ in 0 ..< 10000 {
                counter.incrementCounter()
            }
        }

        let task2 = Task {
            for _ in 0 ..< 10000 {
                counter.incrementCounter()
            }
        }

        await task1.result
        await task2.result

    }.result

    print("class counter count :", counter.counter)
}

await testActorCounter()
await testClassCounter()

이렇게 한번은 actor 카운터로, 다른 한번은 class 카운터로 테스트를 해 보았다. 과연, 카운트 결과는 어떨까?

actor counter count : 20000
class counter count : 12220

두 개의 카운터에서 각각 10000을 카운팅하므로, 마지막 결과는 20000이 되어야 한다.

class 카운터의 결과는 할 때마다 바뀐다. 하지만 actor 카운터는 언제나 정확한 카운트 결과를 보여준다.

두 개의 카운터의 정의는 class 라는 키워드만 actor 라는 키워드로 바꾸었고, 카운터를 사용할 때, await 를 붙여주어야 하는 부분들만 잘 수정해 주면, race condition 으로 인한 누락된 카운트 문제가 해결된다.

class 와 actor 구현의 차이점을 비교해보면 다음과 같다.

counter 객체의 method 를 호출할 때, 변수의 값을 확인할 때, await 키워드가 추가된다. 

728x90