開発

Unity非同期タスク

非同期プログラム

Meta XR Core SDKの多くの操作は非同期です。SceneSpatial Anchorsに関連するものは特にそうです。例えば、空間アンカーを保存するには、数フレームがかかる場合があります。非同期操作は将来いつか結果を生み出します。フレームワークによっては、これは未来と約束と呼ばれています。
非同期操作は困難な可能性があります。操作を開始するコードは結果を消費するコードから分離している可能性があるためです。Meta XR Core SDKは、非同期操作を容易にするいくつかのメカニズムを提供しています。

タスクベースのプログラミング

C#はasync/awaitパターンを「タスク」でサポートし、より自然なコードフローを可能にします。
var result = await anchor.SaveAsync();
C#のasyncとawaitのサポートについての詳細については、Microsoftのasynchronous programming with async and awaitの記事をご覧ください。
Meta XR Core SDKは、OVRTaskでタスクベースのプログラミングモデルをサポートしています。それはSystem.Threading.Tasks.Taskに似ていますが、次のようないくつかの重要な違いもあります。
  • バリュータイプなので、割り当てなしのオブジェクトです。
  • OVRTaskはキャンセルできません。
  • 結果は一度しか取得できません(ValueTaskと同様です)。
  • OVRTaskはスレッドをかけたり、メインスレッドをブロックしたりすることもできません(WaitAllはサポートしていません)。

ovrTaskの使用

Core SDKの多くのメソッドはOVRTaskを返します。OVRTaskを使うには3つの方法があります。
  1. タスクを待つ(await SomeAsyncOperation())
  2. コールバック (task.ContinueWith)
  3. 完了をポーリング (task.IsCompleted)

待つ

awaitはコードを直線的に構造する便利な方法を提供します。
async void OnButtonPress() {
    // Inform user the operation is beginning
    _ui.SetPendingIconEnabled(true);

    // Initiate the operation and await the result
    // (may take multiple frames)
    var result = await _anchor.SaveAsync();

    // Operation done; update UI
    _ui.SetPendingIconEnabled(false);

    // Process the result
    if (result) {
        // do something
    } else {
        // inform user
    }
}
注: これらの方法ではasyncキーワードを使用する必要があります。

コールバック

コールバックで OVRTask を使用するには、ContinueWith メソッドを使用します。
void SaveAnchor(OVRSpatialAnchor anchor) {
    // Inform user the operation is beginning
    _ui.SetPendingIconEnabled(true);

    // Save and await the result (may take multiple frames)
    anchor.SaveAsync().ContinueWith(OnSaveComplete);
}

void OnSaveComplete(bool success) {
    _ui.SetPendingIconEnabled(false);
    Debug.Log($"SaveAnchor completed with result {success}");
}
注:コールバックを提供したタスクをawaitしてはいけません。
以下の行為は認められていません。
async void OnButtonPress() {
    var task = _anchor.SaveAsync();

    task.ContinueWith(OnSave);

    await task; // error; throws InvalidOperationException because
                // the task is already being used with ContinueWith
}

追加状態をキャプチャ

コールバックを使用する場合、タスクに関連した情報をもっと覚えておく必要があることが多いです。ContinueWithには追加状態を捉えるオーバーロードがあります。上の例では、OnSaveCompleteの方法では他の文脈なしに操作結果のみを得ることができます。ContinueWithは、結果と共に追加状態を提供するためにオプションの2番目のパラメータを受け付けます。
void SaveAnchor(OVRSpatialAnchor anchor) {
    // Inform user the operation is beginning
    _ui.SetPendingIconEnabled(true);

    // Provide a delegate and capture a reference to the anchor being saved
    anchor.SaveAsync().ContinueWith(OnSaveComplete, anchor);
}

void OnSaveComplete(bool success, OVRSpatialAnchor anchor) {
    _ui.SetPendingIconEnabled(false);
    Debug.Log($"SaveAnchor {anchor.Uuid} completed with result {success}");
}

ポーリング

task.GetResult()で非同期タスクが完了したかどうかをポーリングし、結果を抽出することもできます。
class MyComponent : MonoBehaviour {
    OVRSpatialAnchor _anchor;

    OVRTask<bool>? _saveTask;

    public void OnSaveButtonPressed() {
        _saveTask = _anchor.SaveAsync();
    }

    void Update() {
        if (_saveTask?.IsCompleted == true) {
            var result = _saveTask.GetResult();
            _saveTask = null;

            // use result ...
        }
    }
}
注: 結果を取得できるのは一度のみです。上記の例では、Nullableタスクを使用して、実行中のタスクと、結果を取得できる完了したタスクを区別しました。
ValueTaskと同様に、結果を抽出できるのは一度だけです。
if (task.IsCompleted) {
    var result = task.GetResult(); // okay; result retrieved

    result = task.GetResult(); // error; no result available
}
ポーリングはOVRTaskをコルーチンに変えることも容易にできます。
IEnumerator Save() {
    var task = _anchor.SaveAsync();

    // "Convert" task to a coroutine
    yield return new WaitUntil(() => task.IsCompleted);

    if (task.GetResult()) {
        // ...
    }
}

注意事項

タスクをキャンセル中

OVRTasksはキャンセルできません。これは、タスク自体が何の仕事もしていないからです。むしろ、OSのように低レベルのシステムからのシグナルを待っています。

スレッド処理

C#システムタスクはスレッドを意味する場合が多いものの、OVRタスクは常にメインスレッド上で操作し、メインスレッドメッセージループを使用して結果を受け取ります。OVRTaskで待っているメインスレッドを絶対にブロックしてはいけません。例えば、これは無限ループを作り出します。
var task = SomeAsyncOperation();
while (!task.IsCompleted) {
    // bad; infinite loop
}
同時にこれも作り出します。
// bad; blocks calling thread
Task.WaitAll(Task.Run(async() => anchor.SaveAsync()));
Task.Waitは使わないでください。
同様に、OVRTasksはスレッドセーフではないので、メインスレッドから完了(IsCompleted)と結果(GetResult())のみをチェックすべきです。
ナビゲーションロゴ
日本語
© 2026 Meta