はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】 「ValueTaskSupplement」でValueTaskに対してWhenAny, WhenAllを適応する

はじめに

今回はValueTaskに対してWhenAny, WhenAll, Lazyを適応できるようにするValueTaskSupplementについて紹介したいと思います。

github.com

またLazy(AsyncLazy)に関しては、私自身ちゃんと理解できていなくこの記事には書かないので注意してください。
ちゃんと理解できたらまた別記事で書きたいと思っています。

テスト環境

  • Unity2022.22.1f1
  • ValueTaskSupplement v1.1.0 (2023/2/9時点ではv1.1.0が最新)

依存先

  • System.Buffers v4.5.0 or later
  • System.Memory v4.5.3 or later
  • System.Threading.Tasks.Extensions v4.5.3 or later

インストール

以下の操作を行います。

  1. nuget.orgからDownload packageを選択、valuetasksupplement.1.1.0.nupkgをダウンロード
  2. 拡張子を.zipに変更し解凍
  3. valuetasksupplement.1.1.0/lib/netstandard2.0/ValueTaskSupplement.dllUnityPluginsにインポート

また依存先のライブラリを入れなくても、Unity2022.22.1f1では動作しました。

www.nuget.org

使い方

private async void Start()
{
    // -----------------------
    // ------- WhenAll -------
    // -----------------------
    var (x0, y0) = await ValueTaskEx.WhenAll(HogeAsync(), FugaAsync());
    Debug.Log($"x0 : {x0}, y0 : {y0}"); // x0 : 1, y0 : 2

    // 以下のような書き方もできます
    var result = await new[] {HogeAsync(), FugaAsync()};
    Debug.Log($"result[0] : {result[0]}, result[1] : {result[1]}"); // result[0] : 1, result[1] : 2

    // 以下の書き方も
    var (x1, y1) = await (HogeAsync(), FugaAsync());
    Debug.Log($"x1 : {x1}, y1 : {y1}"); // x1 : 1, y1 : 2


    // -----------------------
    // ------- WhenAny -------
    // -----------------------
    var (winArgumentIndex, a, b) = await ValueTaskEx.WhenAny(HogeAsync(), FugaAsync());
    Debug.Log(winArgumentIndex == 0 ? $"a : {a}" : $"b : {b}"); // a : 1

    // Timeoutなどで活用できるようなメソッド
    // ValueTask<(bool hasResultLeft, T result)> WhenAny<T>(ValueTask<T> left, Task right);
    var (index, left) = await ValueTaskEx.WhenAny(HogeAsync(), Task.Delay(TimeSpan.FromSeconds(1)));
    Debug.Log($"index : {index}, left : {left}"); // index : True, left : 1

    // ValueTask<(bool hasResultLeft, T result)> WhenAny<T>(ValueTask<T> left, ValueTask right);
    var (index1, left1) = await ValueTaskEx.WhenAny(HogeAsync(), DelayAsync());
    Debug.Log($"index1 : {index1}, left1 : {left1}"); // index1 : True, left1 : 1
}

private static async ValueTask<int> HogeAsync()
{
    await Task.Delay(TimeSpan.FromSeconds(0.5f));
    return 1;
}

private static async ValueTask<int> FugaAsync()
{
    await Task.Delay(TimeSpan.FromSeconds(2));
    return 2;
}

private static async ValueTask DelayAsync()
{
    if (DateTime.Now.Second == 0) return;
    await Task.Delay(TimeSpan.FromSeconds(1));
}


めちゃめちゃ便利です。