次の方法で共有


非同期プログラミングの設計の目標と改善点

このトピックでは、Microsoft Game Development Kit (GDK)の新しい非同期プログラミングモデル作成時に設定されたデザインの目標について説明します。 開発者のフィードバックに応じて、Xbox One ソフトウェア開発キット モデルから行われた改善についても説明します。

このトピックの内容は以下のとおりです。

概要

Microsoft Game Development Kit (GDK) は、高度にカスタマイズおよび制御された実行動作を実現するだけでなく、処理とメモリのオーバーヘッドを低く抑えながら、新しい非同期プログラミング モデルを導入しました。 Microsoft Game Development Kit (GDK) のすべての非同期 API 呼び出しは、このモデルを使用して一貫性を保ちます。 ただし、独自のタスクと非同期システムで、非同期ライブラリを直接使用して、タスクのキューイングおよびディスパッチを管理できます。

以前の Xbox 開発キット 非同期モデルおよび開発者からの情報を学習します。 Microsoft Game Development Kit (GDK) の新しいソリューションは、開発者が非同期タスクの実行状況を完全に制御できるように設計されています。 スレッドデザインは、シングル スレッドでの同期実行であっても、特定の優先度やアフィニティマスクを使用したタイトル スレッドでの並列実行であっても使用できます。 Xbox One ソフトウェア開発キットは、システム スレッド プールのみを使用しました。

Microsoft Game Development Kit (GDK) パラダイム シフトは、Win32 スタイルのフラット C または単純な C++ API を使用して、Xbox Oneソフトウェア開発キット ソリューションの内容を改善します。 これにより、メモリの割り当てと割り当て解除のタイミングを直接管理できます。 パフォーマンスをより簡単に調べることができ、ほとんどの API 呼び出し (およびタスクの実行に使用されるすべての非同期ライブラリ API 呼び出し) には、高パフォーマンスの保証が付属しています。

設計目標

非同期ライブラリは、重要な目標があって設計されており、API やシステムから最小限のオーバーヘッドでタイトルが最大のパフォーマンスを得られるようにします。 以下の一覧には、いくつかのハイ レベルな目標が含まれています。

  • 非同期コードは一貫性があり、理解や特定が簡単であること
  • コールバックの実行動作を完全に自由に管理できます。
  • スレッドは自由に利用できること
  • パフォーマンスとメモリ使用状況は一貫性があり管理しやすいこと
  • タスクを実行するシステムのオーバーヘッドは低く、メイン スレッドで使用できること
  • 非同期ライブラリは、Microsoft Game Development Kit (GDK) API の使用のみを目的として予約しないでください。

これらの目標の一部は、このトピックで説明されています。その他については、後の「Xbox One ソフトウェア開発キットからの改善」を参照してください。

一貫性とクロスプラットフォーム

一貫性により、非同期 API の記述方法や動作について、次が期待できます。

  • メソッドとデータの前には X が付き、その後にライブラリ名が続きます。
  • 通常のエラーは、HRESULT エラーコードで報告されます
  • Microsoft Game Development Kit (GDK) 全体のすべての非同期呼び出しでは、XAsyncBlock が使用されます。
  • Async Microsoft Game Development Kit (GDK) の開始メソッドは、Asyncで後置されています。
  • Async Microsoft Game Development Kit (GDK) の結果メソッドは、Resultで後置されています。

クロスプラットフォームであるということは、Microsoft Game Development Kit (GDK) が対象にできるすべてのプラットフォームで同じ非同期 API 呼び出しを使うことができます。 これらのプラットフォームには、Windows PC認可が必須ですXbox One ファミリー本体、Xbox Series 本体 (NDA トピック)認可が必須ですが含まれます。

Microsoft Game Development Kit (GDK) API 呼び出しまたは独自の機能に対して非同期ライブラリを使用しているかどうかにかかわらず、XAsyncBlock を設定し非同期メソッドを開始するというプロセスは常に同じです。 ライブラリによって提供された非同期メソッドは常に、実装用の非同期ライブラリを使用します。 次の表は、公開された非同期メソッドを持つライブラリを示しています。

ライブラリ 非同期の使用
XUser Xbox サービス ユーザーの管理 XUserAddAsync
XUserAddResult
XUserGetGamerPictureAsync
XUserGetGamerPictureResult
XGameSave ゲームのセーブの読み取り、書き込み、管理 XGameSaveInitializeProviderAsync
XGameSaveInitializeProviderResult
XGameSaveSubmitUpdateAsync
XGameSaveSubmitUpdateResult
XPackage ゲームのインストールの観察および管理 XPackageInstallChunksAsync
XPackageInstallChunksResult
XGameUI システム ダイアログおよびその他のシェル UI の活用 XGameUiShowMessageDialogAsync
XGameUiShowMessageDialogResult
XGameUiShowSendGameInviteAsync
XGameUiShowSendGameInviteResult

徹底的な開発者の制御

新しい非同期ライブラリの重要な部分は、タイトルに可能な限り最適な使い方を実現できるよう開発者が完全に制御できることです。 つまり次を含め、モデルの多くの部分をカスタマイズできます。

タスク キューが 作成されている場合、次の表に示すように、2 つのポートのコールバックをどのようにディスパッチするかをカスタマイズできます。

ポートモード 動作
ThreadPool キューに登録されたコールバックは、システムプールスレッドのバックグラウンドで自動的かつ同時にディスパッチされます。
SerializedThreadPool キューに登録されたコールバックは、システムプールスレッドのバックグラウンドで自動的にディスパッチされます。 ただし、重複なく続けて実行させるため、アクティブにすることができるのは常に 1 つのコールバックだけです。
Immediate コールバックは、コールバックを後回しにしてキューに入れるのではなく、呼び出し元のスタック フレーム内ですぐに実行されます。 作業ポートが Immediate の場合は、非同期呼び出しの開始時にワーク コールバックが実行されます。 完了ポートが Immediate の場合は、同じスタックフレームで作業のコールバックが終了した後に、完了コールバックが実行されます。
Manual このモードでポートに格納されているコールバックが自動的にディスパッチされることはありません。 ポートのコールバックを手動で実行するには XTaskQueueDispatch を呼び出す必要があります。 呼び出しパターンにより、コールバックがどのようにスレッド化され並列化されるのかが決まります。

XTaskQueueSetCurrentProcessTaskQueue を使用してタスクキューが指定されていない場合は、タイトルで使用される既定値のタスクキューを置き換えることができます。 タスクキューが常に指定されるようにするには、nullptr でその関数を使用して、既定のキューを削除することもできます。 この操作を行うと、タスクキューが指定されていないときにエラーが発生します。

非同期呼び出しにポーリングを使用して完了確認する必要がある場合は、XAsyncGetStatus を使用してリターンコードを確認できます。

任意のスレッド状況

手動ディスパッチを使用するようにタスクキューポートが構成されている場合、ポートがディスパッチされるタイミングや方法に制限はありません。 非同期ライブラリは、ロックを気にすることなく、カスタムのスレッド化および同時実行動作を実現するように実装されておりスレッドセーフです。 クリティカル セクション、インターロックされた操作、およびその他の関連マルチスレッド構造は、コールバック内で使用されているユーザー データを保護するためだけに必要です。非同期システムでは必要ありません。

独自のスレッドを使用する場合は、実装事例で必要な場合に、アフィニティマスクとスレッドの優先順位を自由に設定できます。 Windows Message Loop を使用してもディスパッチを処理できます。 手動のポート内におけるタスクのコールバック実行動作は、図 1 と図 2 に示すように、スレッドがどのように XTaskQueueDispatch を 呼び出すよう設定されているかに完全に依存します。

図 1. 1 つのスレッドのコールバック実行動作を示します。

1 つのスレッドのコールバック実行動作を示すスクリーンショット

図 2. 複数のスレッドのオブジェクトの実行動作を示します。

複数のスレッドのオブジェクトの実行動作を示すスクリーンショット

Xbox One ソフトウェア開発キットからの改善

フィードバックへの対応や過去の解決策の改善は、Microsoft Game Development Kit (GDK) (NDA トピック)にとって非常に重要です認可が必須です。 以下のサブセクションでは、Xbox One ソフトウェア開発キットの非同期プログラミングと比べた、いくつかの重要な改善点について説明します。

C++/CLIは無い (WinRT)

Xbox One ソフトウェア開発キットでは、非同期関数の動作に C++/CLI (WinRT) を使用する必要があります。 これにより、システムは Xbox サービスなどのサービスへの呼び出しを管理し、リソースの漏洩やエラーなどの問題は発生しません。 ただし、システムの暗黙的なタイム スライスとリソースの使用について、新しいコーディング構文とアカウントを学ぶ必要があります。

Microsoft Game Development Kit (GDK) 非同期モデル認可が必須です は、パラダイムを非同期ライブラリ用の Win32 スタイルの C スタイル API モデルに切り替えます。 Microsoft Game Development Kit (GDK) コードは、マネージド WinRT エコシステムを統合することなく、C/C++ プロジェクトで直接使用できます。 結果として、すべての割り当てと動作が分離され、システムスレッドの背景動作が最小限になり詳しく理解されます。

スレッド動作を完全に制御

Xbox One ソフトウェア開発キットには非同期呼び出しを処理するための方法が 1 つあります。システムプールスレッドで同時に実行さる方法です。 コントロールの範囲は、システムスレッドプールの調整に制限されています。

Microsoft Game Development Kit (GDK) では、Xbox One ソフトウェア開発キットで説明されているように、スレッドは以前と同様にシステム スレッド プールを使用できます。また、手動スレッドでカスタマイズして、アプリケーションに必要な動作を構築できます。 手動スレッド化では、XTaskQueueDispatch を呼び出す方法とタイミングによって、コールバック実行動作が決まります。 この関数が 1 つのスレッドでのみ呼び出された場合、動作はスレッドで同期実行されます。 複数のスレッドが同時に関数を呼び出す場合、各呼び出しはタスクキューから異なるコールバックを取得し、それらを並列に実行します。

コールバックの実行動作の違いについては、このトピックの「徹底的な開発者の制御」セクションで説明しました。

例外の代わりのエラーコード

Microsoft Game Development Kit (GDK) には、古いテクノロジと新しいテクノロジの両方が含まれています。 結果として、エラー処理がライブラリ間で異なる場合があります。 非同期ライブラリは、「例外なし」として設計されています。 これは、呼び出しエラー、フロー制御、ステータスレポート、またはその他のランタイム目的のために例外が使用されないことを意味します。 タイトルでは独自の例外処理を使用できます。

ほとんどのエラーと状態コードは、標準の Win32 コーディングスタイルで HRESULT コードによって報告されています。 結果の状態コードが重要ではない場合は、ブール値が使用されることがあります。 API メソッドで一般的なエラーが生成されることが予想される場合、これらのエラーは、その原因の説明と共にドキュメント内に一覧表示されます。

HRESULT コードが使用されるため、コードをチェックする簡単なパターンは、Windows SUCCESS()FAILED() マクロの使用になります。 特定のエラーコードを確認して進め方を判断する場合は、HRESULTの値をチェックします。

Microsoft Game Development Kit (GDK) のエラー処理の詳細については、「Microsoft Game Development Kit (GDK) におけるエラー処理の結果」ページを参照してください。

ガーベジ コレクション無し

Microsoft Game Development Kit (GDK) には C++/CLI (WinRT) サポートはありません。だからつまり、実行時にバックグラウンドで発生するガベージ コレクションもありません。 すべての追跡された OS の割り当ては、ライブラリによって提供される直接HANDLEオブジェクトまたはカスタム ハンドル typedefs によって表現されます。

ハンドルを使用して、呼び出し元が管理する割当/割当のタイミングや動作、パフォーマンスを設定することができます。 このような割り当ておよび解放は、必要に応じてローダー スレッドをサポートするためオフにし、結果として、パフォーマンスの遅延を回避できます。 パフォーマンスが最高状態であるときは、予期せず割り当て解放が発生することはありません。

ただし、リソースの追跡とメモリ漏洩の回避はユーザーの責任になります。 割り当てられたハンドルは不要になると解放されるのでご注意ください。

高パフォーマンスの保証

マネージド COM フレームワークの使用に伴う Xbox One ソフトウェア開発キット非同期モデルは、原因となることがほとんどないような予想外のメモリやパフォーマンスの一時的な中断に対応します。 ただし、Microsoft Game Development Kit (GDK) モデルでは、一貫性のあるパフォーマンスとメモリのフットプリントが保証されます。

スレッドを制御できるため、プロファイラーやカスタム コードを使用してシステム呼び出しのパフォーマンスをより簡単に調べることができます。 ATG 非同期プログラミングのサンプルには、これらの時間を計測するためのテストが組み込まれています。 図 3 のグラフは、カスタム非同期プロバイダーを使用して非同期タスクの管理に費やされた時間を示しています。 テストの実行に使用されるカスタムスレッドは、可能な限り早くコールバックされます。

図 3. 非同期システムのオーバーヘッドを測定する図を示します

非同期システムのオーバーヘッドを測定する図を示すスクリーンショット

実際のシステムのオーバーヘッドは非常に低いです。 オーバーヘッドコストは主に、スレッドがタスクキューポートのディスパッチを待っているために起こります。 オーバーヘッドコストを無視した全体的な非同期タスク時間は、タスクのコールバック内での実際の作業時間です。

時間依存のスレッド

時間依存スレッドは、ブロックさせたくない、または予想外に長時間実行させたくないタイトルスレッドを識別するために Microsoft Game Development Kit (GDK) で使用する新しい仕様です。 ユーザーは、XThreadSetTimeSensitiveの呼び出しを使用して、タイトルスレッドに時間依存型であるとマークをつけることができます。 スレッドが時間依存型としてマークされている場合、一貫性のある信頼できるランタイム パフォーマンスを実現しない (「時間依存セーフ」と定義されていない) スレッドにおける Microsoft Game Development Kit (GDK) API メソッドは、デバッグ アサートをトリガーします。

これらの時間依存型セーフ メソッドでは、実装側で以下が保証されます。

  • オンデマンドの読み込みや初期化は実行されない。
  • VM またはプロセスの境界を超えて呼び出されることはない。
  • メモリ割り当てに制限がある。

これにより、時間依存型セーフ メソッドはすべて、入力が同じであると一貫性のあるタイミングで実行され、予期せずにパフォーマンスが急上昇することはありません。 多くの Microsoft Game Development Kit (GDK) メソッドは、内部的に時間依存セーフとして マークされ、スレッドは時間依存型としてマーク付けしなくても必ず時間依存セーフメソッドを呼び出すことができます。

ほとんどの非同期 API メソッドは、時間依存セーフ メソッドです。 タスク キューのセットアップや他の頻度の少ない呼び出しには関連していないいくつかの方法は、通常、ロード時または初期化時に実行されます。 非同期タスクの開始、管理、キャンセル、完了、またはその他の操作に関連するすべてのメソッドは、時間依存セーフです。 安全でない関数の詳細については、「時間依存のスレッド」トピックの「Unsafe functions for time-sensitive threads (時間依存型スレッドの安全でない関数)」を参照してください。

Microsoft Game Development Kit (GDK) API 呼び出し以外の一般的な使用法

Microsoft Game Development Kit (GDK) の非同期ライブラリは汎用で、API 呼び出しの使用に制限されていません。 Microsoft Game Development Kit (GDK) によって提供されている非同期呼び出しは、内部的に非同期ライブラリを使用し、タスクを開始し、結果を取得するアクションの一貫性のあるメソッドを提供します。 非 GDK API の目的でライブラリを使用する方法の詳細については、「サンプル コード」を参照してください。

このセットアップでは、非同期タスクを開始することは Microsoft Game Development Kit (GDK) 関数かカスタム パターンであるかにかかわらず、XAsyncBlock がタスク用にセットアップされ、その後タスクが開始されます。 タスクの開始には Microsoft Game Development Kit (GDK) API 関数またはユーザー設定のタイトルメソッドを使用できます。

タイトルに関係なく非同期ライブラリを自由に使用することができます。

関連項目

非同期プログラミング モデル
タスク キューの設計