やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

C#8.0非同期イテレータ

 非同期に繰り返せる何か。途中でキャンセルもできる。

成果物

情報源

コード

0

static async IAsyncEnumerable<int> GenerateAsync()
{
    for (int i = 0; i<10; i++)
    {
        yield return i;
        await Task.Delay(TimeSpan.FromSeconds(1));
    }
}

 上記イテレータを消費するには以下のようなforeachを書く。

static async Task Main(string[] args)
{
    await foreach (var x in GenerateAsync()) { Console.WriteLine($"{x}"); }
}

1

 キャンセルするまで取得する。

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
 
public class Code1
{
    public async Task Run()
    {
        var cts = new CancellationTokenSource();
 
        var enumerable = GenerateAsync();
 
        var enumerator = enumerable.GetAsyncEnumerator(cts.Token);
 
        // キャンセル前なので値が取れる
        await enumerator.MoveNextAsync();
        Console.WriteLine(enumerator.Current);
 
        cts.Cancel();
 
        // キャンセルしたので止まる
        if (!await enumerator.MoveNextAsync())
            Console.WriteLine("終了");
    }
 
    // キャンセルするまで1秒ごとに値を生成する
    private async IAsyncEnumerable<int> GenerateAsync([EnumeratorCancellation] CancellationToken ct = default)
    {
        var i = 0;
        while (!ct.IsCancellationRequested)
        {
            yield return i;
            await Task.Delay(TimeSpan.FromSeconds(1));
            ++i;
        }
    }
}

所感

 キャンセルするまで実行するのは素敵。フィボナッチ数列や乱数など何かを永遠に生成するときに使えそう。

 つまり、非同期イテレータは遅延評価を非同期にしたいとき使えるってことかな?

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux