await で待機して結果を受け取れるあたりも一緒です
ただ Promise だとネストしても自動で 1 段にしてくれますが Task はそういうことがなく(
設定次第) 値を取り出すために二重三重に await をしないといけなかったりで Promise よりも使いづらかったです
また非同期処理を呼び出すところが Node.js ほどないのであまり使ってなかったです
JavaScript だとシングルスレッドでしか動かないので 不要なところを Promise 化しても 長い処理の途中で別の処理を行えるだけで全体としての実行時間は変わりません
ですが Task はマルチスレッドで動いてくれます
JavaScript でいう Worker を使うようなことを手軽にできます
この利点を考えたら普段から積極的に使っていく方がいいのかもしれない と思いました
例えばこういう処理があったとします
var start = DateTime.Now;
var list = new List<int>();
for (var i = 0; i < 12; i++)
{
list.Add(i);
}
var middle = DateTime.Now;
System.Console.WriteLine(middle - start);
var result = list.Select(x =>
{
var n = 0;
for (var i = 0; i < 100000000; i++)
{
n++;
}
return n;
}).ToList();
System.Console.WriteLine(string.Join(",", result));
var end = DateTime.Now;
System.Console.WriteLine(end - middle);
00:00:00.0076682
100000000,100000000,100000000,100000000,100000000,100000000,100000000,100000000,100000000,100000000,100000000,100000000
00:00:02.4401087
リストの要素のそれぞれに重たい処理を行います
今回だと 1 億回インクリメントです
全体で 2 秒ほどかかってます
これを Task 化します
リストのそれぞれの処理を Task にして最後にまとめて待機します
var start = DateTime.Now;
var list = new List<int>();
for (var i = 0; i < 12; i++)
{
list.Add(i);
}
var middle = DateTime.Now;
System.Console.WriteLine(middle - start);
var tasks = list.Select(x =>
Task.Run(() =>
{
var n = 0;
for (var i = 0; i < 100000000; i++)
{
n++;
}
return n;
})
);
var result = await Task.WhenAll(tasks);
System.Console.WriteLine(string.Join(",", result));
var end = DateTime.Now;
System.Console.WriteLine(end - middle);
00:00:00.0075865
100000000,100000000,100000000,100000000,100000000,100000000,100000000,100000000,100000000,100000000,100000000,100000000
00:00:00.3334272
0.3 秒程度になりました
別スレッドになるので JavaScript の Worker みたいに変数共有の面倒さがあったりするのかと思いましたが 普通に Task の中から外側の変数にアクセスできました
参照のみでなく更新もできます
各 Task が結果を返すのではなく Task 外の List に結果を追加するようしてみるとこんな感じです
var start = DateTime.Now;
var list = new List<int>();
for (var i = 0; i < 12; i++)
{
list.Add(i);
}
var middle = DateTime.Now;
System.Console.WriteLine(middle - start);
var result = new List<int>();
var tasks = list.Select((x, i) =>
Task.Run(() =>
{
var n = i;
for (var i = 0; i < 100000000; i++)
{
n++;
}
result.Add(n);
})
);
await Task.WhenAll(tasks);
System.Console.WriteLine(string.Join(",", result));
var end = DateTime.Now;
System.Console.WriteLine(end - middle);
00:00:00.0069215
100000000,100000001,100000003,100000002,100000004,100000006,100000005,100000008,100000007,100000009,100000010,100000011
00:00:00.3152148
ただ並列処理になるのでこういうことをすると結果の順番はバラバラです
あとから元データと紐付けるのが面倒なので Add ではなくインデックスを使って指定の場所を更新するか Select にしてそれぞれが結果を返す形でよさそうです