teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

大事なこと

2019/02/05 00:35

投稿

tamoto
tamoto

スコア4346

answer CHANGED
@@ -9,9 +9,9 @@
9
9
 
10
10
  ---
11
11
 
12
- ちなみに、前回の質問のコメントで`tasks.foreach(t=>t.Result);`としているのは、その手法をあえて採用する価値が全く無いことは置いといて、「その直前で`await Task.WhenAll(tasks.ToArray());`をしている場合は安全」です。何故かと言うと、`WhenAll`によって「`tasks`の全てのTaskが完全に完了していることが保証されている」からです。これの意味が完全に分かる頃には、どうして`.Result`を使ってはいけないか、どこに`.Result`を使っても安全か、も分かっているはずです。
12
+ ちなみに、前回の質問のコメントで`tasks.ForEach(t=>t.Result);`としているのは、その手法をあえて採用する価値が全く無いことは置いといて、「その直前で`await Task.WhenAll(tasks.ToArray());`をしている場合は安全」です。何故かと言うと、`WhenAll`によって「`tasks`の全てのTaskが完全に完了していることが保証されている」からです。これの意味が完全に分かる頃には、どうして`.Result`を使ってはいけないか、どこに`.Result`を使っても安全か、も分かっているはずです。
13
13
 
14
- 以下に前回の質問のコードの重点を整理しました。**どちらでも同じ結果は得られる**ため、「**あえて推奨されないやり方を選ぶ理由があるならそうすれば良い**」というのが結論ですね。
14
+ 以下に前回の質問のコードの重点を整理しました。**どちらでも同じ結果は得られる**ため、「**あえて推奨されないやり方を選ぶ理由があるならそうすれば良い**」というのが結論ですね。ただし、「`Task.WhenAll`を`await`しない」というのは論外です。
15
15
 
16
16
  推奨されるやり方:
17
17
  ```csharp
@@ -24,4 +24,17 @@
24
24
  ```csharp
25
25
  await Task.WhenAll(tasks.ToArray());
26
26
  tasks.ForEach(x => x.Result);
27
+ ```
28
+
29
+
30
+ 論外、デッドロックが発生する可能性がある:
31
+ ```csharp
32
+ var result = Task.WhenAll(tasks.ToArray());
33
+ tasks.ForEach(x => x.Result);
34
+
35
+ /*---------------------------------------*/
36
+
37
+ var result = Task.WhenAll(tasks.ToArray());
38
+ foreach (var r in result.Result)
39
+ Console.WriteLine(r);
27
40
  ```

1

追記

2019/02/05 00:35

投稿

tamoto
tamoto

スコア4346

answer CHANGED
@@ -7,4 +7,21 @@
7
7
  実際、**限られた状況ではどちらでも同じ結果を得ることが可能**です。しかし、`.Result`では非同期のメリットが一切得られなくなるため、このシーンで採用する価値は皆無です。
8
8
  さらに、`.Result`の手法には大きな問題があります。それは、「非同期コンテキストを無理に同期することになるため、デッドロックを引き起こす可能性がある」ことです。これはちょっとしたコードでも簡単に発生するので、「使っても絶対に安全な場面である」「何故安全であるか理解している」「その上で`.Result`を使うことに説得力がある理由が存在する」を全て満たす場合にのみ使ってください。つまりは、実質使用禁止ということです。
9
9
 
10
- ちなみに、前回の質問のコメントで`tasks.foreach(t=>t.Result);`としているのは、その手法をあえて採用する価値が全く無いことは置いといて、「その直前で`await Task.WhenAll(tasks.ToArray());`をしている場合は安全」です。何故かと言うと、`WhenAll`によって「`tasks`の全てのTaskが完全に完了していることが保証されている」からです。これの意味が完全に分かる頃には、どうして`.Result`を使ってはいけないか、どこに`.Result`を使っても安全か、も分かっているはずです。
10
+ ---
11
+
12
+ ちなみに、前回の質問のコメントで`tasks.foreach(t=>t.Result);`としているのは、その手法をあえて採用する価値が全く無いことは置いといて、「その直前で`await Task.WhenAll(tasks.ToArray());`をしている場合は安全」です。何故かと言うと、`WhenAll`によって「`tasks`の全てのTaskが完全に完了していることが保証されている」からです。これの意味が完全に分かる頃には、どうして`.Result`を使ってはいけないか、どこに`.Result`を使っても安全か、も分かっているはずです。
13
+
14
+ 以下に前回の質問のコードの重点を整理しました。**どちらでも同じ結果は得られる**ため、「**あえて推奨されないやり方を選ぶ理由があるならそうすれば良い**」というのが結論ですね。
15
+
16
+ 推奨されるやり方:
17
+ ```csharp
18
+ var result = await Task.WhenAll(tasks.ToArray());
19
+ foreach (var x in result)
20
+ Console.WriteLine(x);
21
+ ```
22
+
23
+ 推奨されないやり方:
24
+ ```csharp
25
+ await Task.WhenAll(tasks.ToArray());
26
+ tasks.ForEach(x => x.Result);
27
+ ```