C#6.0
.NET Framework 4.6 で開発する上で、
非同期処理について調査をしています。
async/await を使った書き方について、
例えば次のような書き方ができると思います。
C#
1private Task Hoge() 2{ 3 return Task.Run(() => DoWork()); 4} 5 6private async Task HogeAsync() 7{ 8 await Task.Run(() => DoWork()); 9} 10 11private void DoWork() 12{ 13 // 何か処理 14}
Hoge() はタスクを明示的に返すだけのものですが、
HogeAsync() は非同期的に処理をおこなおうとしています。
ところで、この HogeAsync() メソッドの定義の記述方法なのですが、
Task クラスを戻り値として指定していますが、
明示的に return していないため、
通常のメソッドとして見ると違和感を覚えます。
これは await キーワードの裏側に return があるのでしょうか?
その場合、
C#
1private async Task HogeAsync() 2{ 3 await Task.Run(() => DoWork1()); 4 await Task.Run(() => DoWork2()); 5}
このように複数の await を使用するとどうなるのでしょうか。
それとも、async キーワードを伴うメソッドは、
このメソッド全体をタスクとして認識し、
メソッド全体の処理そのものを Task クラスの戻り値とするのでしょうか。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/03/23 14:22
退会済みユーザー
2021/03/23 21:49
回答4件
0
ベストアンサー
これは await キーワードの裏側に return があるのでしょうか?
実際にコンパイラは
csharp
1using System; 2using System.Threading.Tasks; 3 4 5class Test { 6 7 public async Task HogeAsync() 8 { 9 await Task.Run(() => DoWork1()); 10 await Task.Run(() => DoWork2()); 11 } 12 13 private void DoWork1() {} 14 private void DoWork2() {} 15 16}
このコードを
csharp
1using System; 2using System.Diagnostics; 3using System.Reflection; 4using System.Runtime.CompilerServices; 5using System.Security; 6using System.Security.Permissions; 7using System.Threading.Tasks; 8 9[assembly: CompilationRelaxations(8)] 10[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] 11[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] 12[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] 13[assembly: AssemblyVersion("0.0.0.0")] 14[module: UnverifiableCode] 15internal class Test 16{ 17 [CompilerGenerated] 18 private sealed class <HogeAsync>d__0 : IAsyncStateMachine 19 { 20 public int <>1__state; 21 22 public AsyncTaskMethodBuilder <>t__builder; 23 24 public Test <>4__this; 25 26 private TaskAwaiter <>u__1; 27 28 private void MoveNext() 29 { 30 int num = <>1__state; 31 try 32 { 33 TaskAwaiter awaiter; 34 TaskAwaiter awaiter2; 35 if (num != 0) 36 { 37 if (num == 1) 38 { 39 awaiter = <>u__1; 40 <>u__1 = default(TaskAwaiter); 41 num = (<>1__state = -1); 42 goto IL_00ef; 43 } 44 awaiter2 = Task.Run(new Action(<>4__this.<HogeAsync>b__0_0)).GetAwaiter(); 45 if (!awaiter2.IsCompleted) 46 { 47 num = (<>1__state = 0); 48 <>u__1 = awaiter2; 49 <HogeAsync>d__0 stateMachine = this; 50 <>t__builder.AwaitUnsafeOnCompleted(ref awaiter2, ref stateMachine); 51 return; 52 } 53 } 54 else 55 { 56 awaiter2 = <>u__1; 57 <>u__1 = default(TaskAwaiter); 58 num = (<>1__state = -1); 59 } 60 awaiter2.GetResult(); 61 awaiter = Task.Run(new Action(<>4__this.<HogeAsync>b__0_1)).GetAwaiter(); 62 if (!awaiter.IsCompleted) 63 { 64 num = (<>1__state = 1); 65 <>u__1 = awaiter; 66 <HogeAsync>d__0 stateMachine = this; 67 <>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); 68 return; 69 } 70 goto IL_00ef; 71 IL_00ef: 72 awaiter.GetResult(); 73 } 74 catch (Exception exception) 75 { 76 <>1__state = -2; 77 <>t__builder.SetException(exception); 78 return; 79 } 80 <>1__state = -2; 81 <>t__builder.SetResult(); 82 } 83 84 void IAsyncStateMachine.MoveNext() 85 { 86 //ILSpy generated this explicit interface implementation from .override directive in MoveNext 87 this.MoveNext(); 88 } 89 90 [DebuggerHidden] 91 private void SetStateMachine(IAsyncStateMachine stateMachine) 92 { 93 } 94 95 void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine) 96 { 97 //ILSpy generated this explicit interface implementation from .override directive in SetStateMachine 98 this.SetStateMachine(stateMachine); 99 } 100 } 101 102 [AsyncStateMachine(typeof(<HogeAsync>d__0))] 103 [DebuggerStepThrough] 104 public Task HogeAsync() 105 { 106 <HogeAsync>d__0 stateMachine = new <HogeAsync>d__0(); 107 stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); 108 stateMachine.<>4__this = this; 109 stateMachine.<>1__state = -1; 110 stateMachine.<>t__builder.Start(ref stateMachine); 111 return stateMachine.<>t__builder.Task; 112 } 113 114 private void DoWork1() 115 { 116 } 117 118 private void DoWork2() 119 { 120 } 121 122 [CompilerGenerated] 123 private void <HogeAsync>b__0_0() 124 { 125 DoWork1(); 126 } 127 128 [CompilerGenerated] 129 private void <HogeAsync>b__0_1() 130 { 131 DoWork2(); 132 } 133}
こう変換してる。
HogeAsync()
を見ての通り、ちゃんとreturnしてます。
投稿2021/03/18 07:11
総合スコア8947
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/03/23 14:47
0
Task クラスを戻り値として指定していますが、
明示的に return していないため、
通常のメソッドとして見ると違和感を覚えます。
戻り値の型が Task の非同期メソッドは呼び出し元に値を返しません。
詳しくは 非同期の戻り値の型 (C#) を参照してください。
これは await キーワードの裏側に return があるのでしょうか?
IL をデコンパイルした C# のコードを確認したら return ステートメントに相応する記述があるかもしれませんが、私には分かりません。
しかし、少なくとも Task の非同期メソッドに return ステートメントを記述する必要はありません。
もちろん、明示的に return ステートメントを記述することはできます。
このように複数の await を使用するとどうなるのでしょうか。
DoWork1 が非同期で呼び出され、DoWork1 が完了するまで HogeAsync は保留となり、DoWork1 が完了すると HogeAsync は再開します。DoWork2 も同様です。
また、どちらのメソッドも値は返されません。
async キーワードを伴うメソッドは、
このメソッド全体をタスクとして認識し、
メソッド全体の処理そのものを Task クラスの戻り値とするのでしょうか。
概ね正しいと思います。
Task クラスに限らず他の型に関しても非同期メソッドの戻り値に指定することが出来ます。
投稿2021/03/18 04:54
編集2021/03/23 15:43総合スコア2663
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/03/18 04:57
2021/03/23 14:32
2021/03/23 15:44 編集
0
違和感を覚えると言われても、返り値を持たない非同期メソッドの定義がそうだからとしか言いようがないです。
非同期の戻り値の型 (C#)
async, awaitは只の糖衣構文なので、実際に内部でどうコンパイルされ、どういう処理をしているかが気になるのであれば、ILSpy等で逆コンパイルして覗いてみればよいのではないでしょうか。
投稿2021/03/18 04:34
退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
質問者さんの別のスレッドで紹介した記事の「async void を避ける」というセクションの説明が参考になりませんか?
以下一部抜粋:
"async Task メソッドまたは async Task<T> メソッドから例外がスローされると、その例外は Task オブジェクトでキャプチャされ、そこで処理されます"
投稿2021/03/18 05:42
退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/03/23 14:40
退会済みユーザー
2021/03/23 21:37
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。