Home » 스터디 » Page 3

스터디

Unmanaged 에 대해 – Swift

그 옛날(?) ARC가 없던 시절에 Objective-C 및 코어 파운데이션에서 객체에 대한 참조수 관리는 완전한 수동 방식에 의존하고 있다. 어떤 객체에 대한 retain(참조수를 늘리는 것) 동작은 반드시 그에 수반하는 release(참조수를 내리는 것) 동작을 필요로 했다. 그리고 이 짝이 제대로 맞지 않으면 객체는 필요한 시점에 사라지고 없거나, 반대로 메모리 누수가 발생했다. 그러던 중 자동 참조수 카운팅(ARC)이 도입되었는데, ARC 환경에서는 모든 retain/release/autorelease 콜이 컴파일러에 의해 코드에 자동으로 삽입되었다. 이는 전체적인 코드량의 감수는 물론 개발 난이도를 매우 낮춰주는 역할을 했다.

ARC가 도입된 이후 Objective-C 메소드에 의해 반환되는 모든 Objective-C 객체와 코어 파운데이션 객체의 메모리 관리는 자동으로 이루어졌다. 하지만 C 함수에 의해 리턴되는 코어 파운데이션 객체는 이러한 은혜를 받지 못했다. 따라서 여기에 속하는 객체들에 대해서는 여전히 CFRetain(), CFRelease()를 호출하거나, __bridge*로 시작하는 함수를 통해 Objecitve-C 객체로 브릿징해야 했다.

더 보기 »Unmanaged 에 대해 – Swift

포인터 관련 메모

타입화된 포인터

Swift는 C API와의 상호작용 혹은 고성능 자료구조의 구현등을 위해 포인터를 통한 메모리 액세스를 제한적으로 지원하고 있습니다. 기본적으로 Swift 타입 혹은 Swift 에서 인식할 수 있는 C 타입에 대한 포인터는 ‘타입화된(typed)’ 포인터라고 하며, UnsafePointer를 사용합니다. UnsafePointer는 제네릭 struct 타입으로 특정 Swift 타입에 대한 포인터로 기능합니다. UnsafePointer는 메모리 주소를 통한 액세스를 허용해주기는 하지만 값의 불변성을 보장하기 때문에 해당 포인터가 가리키는 값(pointee)를 변경하는 것을 허용하지 않습니다. 변수에 대한 포인터는 UnsafeMutablePointer를 별도로 사용합니다.

더 보기 »포인터 관련 메모

(Swift) 프로토콜 그 자체가 자신을 따르지 않는다

Swift 5.1에 추가된 some 키워드 (불투명 리턴 타입)에 관한 Swift 공식 문서를 살펴보다가 이상한 구절을 발견했다.

Another problem with this approach is that the shape transformations don’t nest. The result of flipping a triangle is a value of type Shape, and the protoFlip(_:) function takes an argument of some type that conforms to the Shape protocol. However, a value of a protocol type doesn’t conform to that protocol; the value returned by protoFlip(_:) doesn’t conform to Shape. This means code like protoFlip(protoFlip(smallTriange)) that applies multiple transformations is invalid because the flipped shape isn’t a valid argument to protoFlip(_:).

프로토콜 타입의 값이 그 프로토콜을 따르지 않는다는 것이다. 왱? 이게 뭔말이지? 특정한 프로토콜을 따르는 객체들은 그 실제 타입에 상관없이 해당 프로토콜을 타입처럼 사용할 수 있다고 했는데, 이번에는 프로토콜 타입의 값이 그 프로토콜을 따르지 않는다라니?

더 보기 »(Swift) 프로토콜 그 자체가 자신을 따르지 않는다

Selector를 사용한 소켓 멀티플렉싱

소켓을 사용하여 간단한 서버를 만들 때에는 서버 소켓을 생성하고, 이를 특정한 네트워크 포트에 바인드한 다음, listen() 메소드를 사용해서 해당 포트로 들어올 수 있는 접속 대기열의 크기를 지정합니다. 그런 다음 해당 소켓의 accept() 메소드를 사용해서 클라이언트 소켓을 생성하고, 이 클라이언트 소켓을 통해 클라이언트가 보낸 요청을 읽고, 그에 대한 응답을 보내게 됩니다.

서버 소켓은 클라이언트가 접속할 때마다 ‘서버가 사용하는 클라이언트 소켓’을 따로 생성하고 실제 통신은 두 클라이언트 소켓 사이의 peer-to-peer 방식의 대화가 됩니다. 따라서 하나의 서버 소켓은 여러 클라이언트의 접속을 받을 수 있습니다.

만약 다중 접속을 허용하는 소켓 서버를 파이썬에서 구현한다면 가장 쉬운 방법은 스레드를 사용하는 것입니다. 클라이언트 소켓을 인자로 받는 핸들러 함수를 하나 작성하고, 서버 소켓의 accept() 메소드가 리턴하는 시점에 핸들러 함수에게 클라이언트 소켓을 주고 새로운 스레드에서 작동하도록 시작해주면 됩니다.

여기까지의 작동 모델은 ‘동기식 소켓’을 사용합니다. 동기식 소켓은 send(), recv(), accept() 등의 동작이 모두 블럭되는 소켓입니다. 따라서 스레드가 소켓의 입출력을 기다리는 동안에는 다른 일을 할 수가 없습니다. 그래서 서버 소켓과 클라이언트 소켓들이 동시에 작동할 수 없으니 스레드를 사용하는 것이겠죠.

소켓 라이브러리는 이와 다른 비동기 소켓을 지원하고 있습니다. 비동기 소켓은 소켓을 바인딩하기 전에 sock.setblocking(False)를 명시해서 블록킹 모드를 논블록킹으로 변경해줍니다. 이렇게 만들어진 비동기 소켓을 소켓 API만으로 사용할 수는 없습니다. Python How To 문서는 select.select() 를 사용할 것을 추천합니다만, 이는 문서가 오래되었음을 감안해야 하며 실제 파이썬 공식문서는 보다 고수준으로 설계되어 사용하기 쉬운 selectors 모듈을 쓸 것을 추천하고 있습니다.

이 글에서는 selectors 모듈을 사용하여, 단일 스레드에서 하나의 소켓 서버가 여러 클라이언트의 요청을 처리하는 멀티플렉싱을 어떻게 구현하는지 소개하며, 셀렉터 사용 방법에 대해서 살펴보겠습니다.

더 보기 »Selector를 사용한 소켓 멀티플렉싱

ZMQ 예제 – Poller를 사용하여 종료 시점을 동기화하기

하나의 ZMQ 소켓은 여러 포트에 바인드하거나 커넥트할 수 있어서, 1:N의 연결을 쉽게 구성할 수 있습니다. 하지만 어떤 경우에는 이 다중 접속이 두 개 이상의 소켓을 사용하는 경우도 있습니다. 이런 경우 두 개의 소켓을 동시에 듣는 방법이 필요합니다. ZMQ소켓의 recv() 메소드는 블럭킹 함수이기 때문에 2개 이상의 소켓 중 데이터가 들어온 소켓을 처리하기 위해서는 소켓만으로는 처리할 수 없습니다. ZMQ는 이런 상황에 사용할 수 있는 Poller라는 수단을 제공합니다.

더 보기 »ZMQ 예제 – Poller를 사용하여 종료 시점을 동기화하기

Asyncio – 네트워크 입출력을 위한 스트림

asyncio는 네트워크 입출력을 위한 스트림이라는 타입을 제공하고 있다. 스트림은 네트워크 연결을 만들거나(클라이언트의 connect 동작) 서버를 시작하고(서버의 bind/listen 동작) 연결이 생성되면 해당 연결을 처리하는 핸들러의 인자로 넘겨지게 된다. 비동기 코루틴인 각각의 핸들러는 이 스트림을 이용해서 데이터를 읽거나 전송할 수 있다.

입출력 스트림은 내부적으로 소켓을 감싸고 있으며, 노출되는 API를 통해서 소켓을 기다리고 읽고 쓰는 일련의 작업을 상당히 고수준의 레벨에서 제공해주고 있다.

더 보기 »Asyncio – 네트워크 입출력을 위한 스트림

파이썬 – 클래스를 사용하지 않기

보통 객체 지향 언어를 설명할 때, 객체 지향의 기본적인 개념으로 클래스를 언급하는 경우가 많습니다. 그리고 자바나 C++ 등의 언어에서도 어떤 현실의 문제를 해결할 때, 그에 맞는 클래스부터 설계하는 방식으로 접근하기도 하지요. 파이썬 역시 객체지향 컨셉이 주가 되는 언어이며, 당연하게도 사용자가 직접 원하는 클래스를 정의하여 사용할 수 있습니다. 실제로 파이썬의 모든 것이 객체이기도 하지요.

그럼에도 불구하고 몇몇 특수한 경우를 제외하면 사실 파이썬에서 클래스를 직접 만들어서 사용하는 방식을 그리 권장하고 싶지는 않습니다.

더 보기 »파이썬 – 클래스를 사용하지 않기