非同期に繰り返せる何か。途中でキャンセルもできる。
成果物
情報源
コード
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; } } }
- IAsyncEnumerable
.GetAsyncEnumerator(CancellationToken) - コレクションを非同期に反復処理する列挙子を返します。
- CancellationToken
- 操作を取り消す通知を配信します。
[EnumeratorCancellation]
所感
キャンセルするまで実行するのは素敵。フィボナッチ数列や乱数など何かを永遠に生成するときに使えそう。
つまり、非同期イテレータは遅延評価を非同期にしたいとき使えるってことかな?
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch 9.0 2018-11-13 ※
- bash 4.4.12(1)-release ※
- SQLite 3.29.0 ※
- C# dotnet 3.0.100
$ uname -a Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux