다음을 통해 공유


비동기 프로그래밍 설계 목적 및 개선 사항

이 항목에서는 Microsoft GDK(게임 개발 키트)에 대한 새로운 비동기 프로그래밍 모델을 만들 때 설정한 디자인 목표를 다룹니다. 이 항목에서는 개발자 피드백에 대한 응답으로 Xbox One 소프트웨어 개발 키트 모델에서 개선된 사항도 다룹니다.

이 항목의 내용

소개

Microsoft GDK(게임 개발 키트)는 낮은 처리 및 메모리 오버헤드를 가지면서 고도로 사용자 지정 및 제어 가능한 실행 동작을 제공하도록 설계된 새로운 비동기 프로그래밍 모델을 도입했습니다. Microsoft GDK(게임 개발 키트)의 모든 비동기 API 호출은 이 모델을 사용하여 일관성을 제공합니다. 그러나 작업 대기열과 전달을 관리하기 위해 직접 수행하는 작업과 비동기 시스템에서도 비동기 라이브러리를 사용할 수 있습니다.

이전 Xbox One 소프트웨어 개발 키트 비동기 모델 및 개발자 피드백에서 배운 Microsoft GDK(게임 개발 키트)의 새 솔루션을 사용하면 비동기 작업이 실행되는 방법과 위치를 완벽하게 제어할 수 있습니다. 단일 스레드의 동기식 실행부터 아주 구체적인 우선순위 및 선호도 마스크를 사용한 타이틀 스레드의 병렬 실행까지 모든 스레드 설계를 사용할 수 있습니다. Xbox One 소프트웨어 개발 키트는 시스템 스레드 풀만 사용했습니다.

Microsoft GDK(게임 개발 키트) 패러다임 전환은 Win32 스타일 플랫 C 또는 간단한 C++ API를 사용하여 Xbox One 소프트웨어 개발 키트 솔루션을 개선합니다. 이를 통해 메모리 할당 및 할당 취소 타이밍을 직접 관리할 수 있습니다. 성능을 더욱 쉽게 검사할 수 있고 대부분의 API 호출(및 작업 실행에 사용 되는 모든 비동기 라이브러리 API 호출)에는 고성능 보장이 함께 제공 됩니다.

설계 목표

비동기 라이브러리는 타이틀이 API나 시스템에서 오버헤드를 최소화하여 성능을 최대한 활용할 수 있도록 보장하기 위한 몇 가지 핵심 목표로 설계되었습니다. 다음 목록에는 몇 가지 높은 수준의 목표가 기재되어 있습니다.

  • 비동기 코드는 일관적이며 쉽게 이해 및 식별할 수 있습니다.
  • 콜백 실행 동작을 완전히 관리할 수 있습니다.
  • 원하는 대로 스레드를 사용할 수 있습니다.
  • 성능 및 메모리 사용은 일관적이고 손쉽게 관리할 수 있습니다.
  • 실행 중인 작업의 시스템 오버헤드가 낮고 주 스레드에서 사용할 수 있습니다.
  • 비동기 라이브러리는 Microsoft GDK(게임 개발 키트) API 용도로만 예약되어서는 안 됩니다.

이러한 목표 중 일부는 다음 하위 섹션에서 다루고 나머지는 이 항목의 Xbox One 소프트웨어 개발 키트의 개선 사항 섹션에서 다룹니다.

일관적인 크로스 플랫폼

일관성을 통해 다음과 같은 비동기 API가 작성되고 작동하는 방법에 관한 기대치가 설정됩니다.

  • 메서드와 데이터에 차례로 접두사 ‘X’와(과) 라이브러리 이름이 붙습니다.
  • 일반적인 오류는 HRESULT 오류 코드를 통해 보고됩니다.
  • Microsoft GDK(Game Development Kit)의 모든 비동기 호출은 XAsyncBlock을 사용합니다.
  • 비동기 Microsoft GDK(게임 개발 키트) 시작 메서드는 Async로 접미사로 지정됩니다.
  • 비동기 Microsoft GDK(게임 개발 키트) 결과 메서드는 Result(이)라는 접미사가 붙습니다.

플랫폼 간이라는 것은 Microsoft GDK(게임 개발 키트)가 대상으로 하는 모든 플랫폼에서 동일한 비동기 API 호출을 사용할 수 있음을 의미합니다. 이러한 플랫폼에는 현재 Windows PC(NDA 항목)권한 부여 필요, Xbox One 제품군 콘솔 및 Xbox Series 콘솔(NDA 항목)권한 부여 필요이 포함됩니다.

Microsoft GDK(게임 개발 키트) API 호출에 비동기 라이브러리를 사용하든 자체 기능을 사용하든 XAsyncBlock 설정비동기 메서드 시작 프로세스는 항상 동일합니다. 라이브러리에서 비동기 메서드를 제공하는 경우에는 항상 해당 메서드가 구현에 비동기 라이브러리를 활용합니다. 다음 표에는 노출된 비동기 메서드가 있는 몇 가지 라이브러리가 나열되어 있습니다.

라이브러리 비동기 사용 예제 메서드
XUser Xbox 서비스 사용자 관리 XUserAddAsync,
XUserAddResult,
XUserGetGamerPictureAsync,
XUserGetGamerPictureResult
XGameSave 게임 저장 읽기, 쓰기 및 관리 XGameSaveInitializeProviderAsync,
XGameSaveInitializeProviderResult,
XGameSaveSubmitUpdateAsync,
XGameSaveSubmitUpdateResult
XPackage 게임 설치 관찰 및 관리 XPackageInstallChunksAsync,
XPackageInstallChunksResult
XGameUI 시스템 대화 및 그 외 Shell UI 활용 XGameUiShowMessageDialogAsync,
XGameUiShowMessageDialogResult,
XGameUiShowSendGameInviteAsync,
XGameUiShowSendGameInviteResult

완벽한 개발자 제어

새로운 비동기 라이브러리의 중요한 부분은 타이틀을 가능한 최선의 방법으로 사용하도록 완전하게 제어할 수 있다는 것입니다. 즉, 다음과 같이 모델의 여러 부분을 사용자 지정할 수 있습니다.

작업 대기열이 생성되는 동안 다음 표에 보이는 바와 같이 두 포트에 대한 콜백의 전달 방식을 사용자 지정할 수 있습니다.

포트 모드 동작
ThreadPool 대기열에 추가된 콜백은 시스템 풀 스레드의 백그라운드에서 자동으로 동시에 전달됩니다.
SerializedThreadPool 대기열에 추가된 콜백은 시스템 풀 스레드의 그라운드에서 자동으로 전달됩니다. 하지만 중복 없는 순차적인 실행을 위해 한 번에 하나의 콜백만 활성화될 수 있습니다.
Immediate 콜백은 나중에 콜백을 대기열에 넣는 대신 대기열에 추가하려고 할 때 호출자의 스택 프레임에서 즉시 실행됩니다. 작업 포트가 ‘Immediate’인 경우 작업 콜백은 비동기 호출을 시작할 때 실행됩니다. 완료 포트가 ‘Immediate’인 경우에는 작업 콜백이 동일한 스택 프레임에서 완료된 이후 완료 콜백이 실행됩니다.
Manual 이 모드에서 포트에 추가된 콜백은 자동으로 전달되지 않습니다. 포트에서 콜백을 수동으로 실행하려면 XTaskQueueDispatch를 호출해야 합니다. 호출 패턴에 따라 콜백이 어떻게 스레드되고 동시에 일어나는지 결정됩니다.

어떠한 작업 대기열도 XTaskQueueSetCurrentProcessTaskQueue를 사용하여 지정되지 않은 경우, 타이틀에 의해 사용되지 않는 기본 작업 대기열을 대체할 수 있습니다. 작업 대기열이 항상 지정되게 하고 싶다면 이 함수를 nullptr와(과) 함께 사용하여 기본 대기열을 제거할 수도 있습니다. 이렇게 하면 작업 대기열이 지정되지 않은 경우 오류가 발생합니다.

비동기 호출에 대한 폴링을 사용하여 작업의 완료 시기를 아는 것을 선호하는 경우에는 XAsyncGetStatus를 사용하여 반환 코드를 확인할 수 있습니다.

모든 스레딩 상황

수동 전달을 사용하도록 작업 대기열 포트를 구성할 때는 포트를 전달할 시기나 방식에 제한이 없습니다. 비동기 라이브러리는 구현 시 스레드로부터 안전하므로 사용자 지정 스레딩 및 동시 동작이 잠금 없이 발생할 수 있습니다. 중요한 섹션, 연동된 작업 및 그 외 관련 멀티스레딩 구조는 비동기 시스템이 아닌 콜백 내에서 사용되는 사용자 데이터를 보호하는 경우에만 필요합니다.

자체 스레드를 사용할 때는 구현 사례에 필요한 모든 항목에 대한 선호도 마스크 및 스레드 우선순위를 자유롭게 설정할 수 있습니다. Windows 메시지 루프를 사용해 전달을 처리할 수도 있습니다. 그림 1과 그림 2에서 보이는 바와 같이 수동 포트 내의 작업 콜백 실행 동작은 XTaskQueueDispatch를 호출하기 위해 스레드가 설정된 방법에 전적으로 의존합니다.

그림 1. 하나의 스레드에 대한 콜백 실행 동작 표시

하나의 스레드에 대한 콜백 실행 동작의 스크린샷

그림 2. 다중 스레드의 콜백 실행 동작 표시

다중 스레드의 콜백 실행 동작 스크린샷

Xbox One 소프트웨어 개발 키트의 향상된 기능

피드백에 대한 응답과 이전 솔루션의 개선은 Microsoft GDK(게임 개발 키트)(NDA 항목)를 위해 매우 중요합니다권한 부여 필요. 다음 하위 섹션에는 Microsoft GDK(게임 개발 키트)의 비동기 프로그래밍과 비교하여 이루어진 몇 가지 주요 개선 사항이 나열되어 있습니다.

추가 C++/CLI(WinRT) 없음

Xbox One 소프트웨어 개발 키트는 비동기 기능 동작을 위해 C++/CLI(WinRT)를 사용해야 했습니다. 이를 통해 시스템은 리소스 누수 및 오류와 같은 문제 없이 Xbox 서비스 및 기타 서비스에 대한 호출을 관리했습니다. 그러나 이를 위해서는 새로운 코딩 구문을 배우고 시스템의 암시적 시간 분할 및 리소스 사용을 설명해야 했습니다.

Microsoft GDK(게임 개발 키트) 비동기 모델권한 부여 필요은 비동기 라이브러리용 Win32 스타일 C 스타일 API 모델로 패러다임을 전환합니다. Microsoft GDK(게임 개발 키트) 코드는 관리되는 WinRT 에코시스템을 통합하지 않고 C/C++ 프로젝트에서 직접 사용할 수 있습니다. 따라서 시스템 스레드의 백그라운드 동작을 최소화하고 명확하게 이해할 수 있습니다.

스레딩 동작의 완벽한 제어

Xbox One 소프트웨어 개발 키트에는 비동기식 호출을 처리하는 단일 방법이 있었는데 시스템 풀 스레드에서 동시에 실행하는 것이었습니다. 제어 범위도 시스템 스레드 풀 조정으로 제한되었습니다.

Microsoft GDK(게임 개발 키트)에서 스레딩은 Xbox One 소프트웨어 개발 키트에 설명된 대로 시스템 스레드 풀을 사용하거나 수동 스레딩으로 사용자 지정하여 응용 프로그램의 동작을 빌드할 수 있습니다. 수동 스레딩을 사용하면 XTaskQueueDispatch이 호출되는 방식과 시기에 따라 콜백 실행 동작이 결정됩니다. 이 함수가 한 개의 스레드에서만 호출되면 동작은 해당 스레드에서 실행되면서 동기화됩니다. 여러 스레드가 해당 함수를 동시에 호출하는 경우, 각 호출은 작업 대기열에서 다른 콜백을 받고 이를 병렬로 실행합니다.

다른 콜백 실행 동작은 앞서 완벽한 개발자 제어 섹션에서 설명하였습니다.

예외 대신 발생하는 오류 코드

Microsoft GDK(게임 개발 키트)에는 기존 기술과 최신 기술이 모두 포함되어 있습니다. 따라서 오류 처리는 라이브러리마다 다를 수 있습니다. 비동기 라이브러리는 "예외 없음"으로 설계되었습니다. 즉, 예외는 호출 오류, 흐름 제어, 상태 보고 또는 다른 런타임 목적에 사용되지 않습니다. 타이틀에 대해 자신만의 예외 처리를 사용할 수 있습니다.

이제 대부분의 오류 및 상태 코드는 표준 Win32 코딩 스타일의 HRESULT 코드를 통해 보고됩니다. 결과 상태 코드가 중요하지 않은 경우에는 부울 값을 사용할 수 있습니다. API 메서드를 사용하여 일반적인 오류를 생성하는 경우 문서에 해당 원인에 대한 설명과 함께 이러한 오류가 표시됩니다.

HRESULT 코드가 사용되기 때문에 코드를 확인하는 간단한 패턴은 Windows SUCCESS()FAILED() 매크로를 사용하는 것입니다. 진행 방법을 결정하기 위해 특정 오류 코드를 확인할 때 HRESULT 값을 확인할 수 있습니다.

Microsoft GDK(게임 개발 키트)의 오류 처리에 대한 자세한 내용은 Microsoft 게임 개발 키트의 오류 처리를 참조하세요.

가비지 수집 없음

Microsoft GDK(게임 개발 키트)에는 C++/CLI(WinRT) 지원이 없기 때문에 런타임 중에 백그라운드에서 발생하는 가비지 수집이 없다는 의미이기도 합니다. 추적된 모든 OS 할당은 직접 HANDLE 개체 또는 라이브러리에서 제공하는 사용자 지정 핸들 typedef로 표시됩니다.

호출자가 핸들을 사용하여 할당/할당 취소 타이밍, 동작 및 성능을 관리할 수 있도록 설정할 수 있습니다. 이러한 할당 및 할당 취소는 성능 장애를 방지하기 위해 지원 로더 스레드로 옮길 수 있습니다. 성능이 가장 중요한 경우에는 할당 취소가 예기치 않게 발생하지 않습니다.

그러나 리소스 추적 및 메모리 누수 방지는 귀하의 책임입니다. 할당된 핸들이 더 이상 필요하지 않을 때 할당 취소되었는지 확인합니다.

뛰어난 성능 보장

관리되는 COM 프레임워크를 사용하는 Xbox One 소프트웨어 개발 키트 비동기식 모델은 때때로 설명하기 어려운 예기치 않은 메모리 및 성능 문제에 적합합니다. 그러나 Microsoft GDK(게임 개발 키트) 모델은 일관된 성능과 메모리 공간을 보장합니다.

스레딩을 제어할 수 있으므로 프로파일러 또는 사용자 지정 코드를 사용하여 시스템 호출 성능을 더욱 쉽게 검사할 수 있습니다. ATG 비동기 프로그래밍 샘플에는 소요된 시간을 측정하는 기본 제공 테스트가 있습니다. 그림 3의 다음 차트는 사용자 지정 비동기 공급자를 사용하여 비동기 작업을 관리하는 데 소요된 시간을 측정합니다. 테스트에 사용되는 사용자 지정 스레드는 콜백을 최대한 빠르게 실행합니다.

그림 3. 비동기 시스템 오버헤드를 측정하는 차트

비동기 시스템 오버헤드를 측정하는 차트의 스크린샷

시스템 오버헤드가 매우 낮습니다. 주로 오버헤드 비용은 스레드가 작업 대기열 포트를 전달할 때까지 대기하는 동안에 발생합니다. 전체 비동기 작업 시간(오버헤드 비용 무시)은 작업 콜백 내의 실제 작업 시간입니다.

시간에 민감한 스레드

시간에 민감한 스레드는 Microsoft 게임 개발 키트(GDK)가 차단 또는 예기치 않게 오래 실행되는 작업을 원하지 않는 타이틀 스레드를 식별하는 데 사용하는 새로운 사양입니다. 사용자는 XThreadSetTimeSensitive 호출을 사용하여 타이틀 스레드를 시간에 민감한 스레드로 표시할 수 있습니다. 스레드가 시간에 민감한 것으로 표시되어 있으면 해당 스레드에서 일관되고 신뢰할 수 있는 런타임 성능("시간에 민감한 안전이 아님")을 제공하지 않는 모든 GDK(Microsoft Game Development Kit) API 메서드가 호출되면 디버그 어설션이 트리거됩니다.

이러한 시간 민감성 관련 안전 메서드는 구현 측면에서 다음과 같은 보장을 포함합니다.

  • 주문형 로딩 또는 초기화가 수행되지 않습니다.
  • 모든 VM 또는 프로세스 경계에 대한 호출이 수행되지 않습니다.
  • 메모리 할당이 제한됩니다.

이 경우 시간 민감성 관련 안전 메서드는 동일한 입력값으로 일관된 시간에 실행되며 예기치 않은 성능의 급상승을 가져오지 않습니다. 대부분의 Microsoft 게임 개발 키트(GDK) 메서드가 내부적으로 시간에 민감하지 않은 것으로 표시되고 스레드는 시간에 민감하지 않은 메서드를 호출할 수 있도록 시간에 민감한 것으로 표시하지 않아도 됩니다.

대부분의 비동기 API 메서드는 시간에 민감하지 않습니다. 시간에 민감한 일부는 로드 또는 초기화 시간에 수행되는 작업 대기열 설정 및 기타 저빈도 호출과 관련이 있습니다. 비동기 작업의 시작, 관리, 취소, 완료 또는 기타 직접 작업과 관련된 모든 메서드는 시간에 민감하지 않습니다. 불안전 함수에 대한 자세한 내용은 시간에 민감한 스레드 항목 중 시간에 민감한 스레드의 불안전 함수 항목의 섹션을 참조하세요.

Microsoft GDK(게임 개발 키트) API 호출 이외의 일반 사용량

Microsoft GDK(게임 개발 키트)용 비동기 라이브러리는 일반적이며 API 호출 사용에 국한되지 않습니다. Microsoft GDK(게임 개발 키트)에서 제공하는 모든 비동기식 호출은 내부적으로 비동기식 라이브러리를 사용하고 작업 시작 및 결과 가져오기를 포함하는 작업에 대해 일관된 메서드를 제공합니다. GDK API 이외의 용도로 라이브러리를 사용하는 방법에 대한 자세한 내용은 샘플 코드를 참조하세요.

이 설정을 사용하면 비동기 작업 시작이 Microsoft GDK(게임 개발 키트) 함수인지 또는 사용자 지정 패턴인지와 무관하게 동일한 프로세스입니다. 즉, 작업에 대한 XAsyncBlock이 설정됨이며 작업이 시작됩니다. 작업 시작은 Microsoft GDK(Game Development Kit) API 함수 또는 사용자 지정 타이틀 메서드일 수 있습니다.

타이틀 전체에 대한 비동기 목적을 위해 비동기 라이브러리를 자유롭게 사용할 수 있습니다.

참고 항목

비동기 프로그래밍 모델
작업 대기열 디자인