質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

スレッドセーフ

マルチスレッド環境において、複数のスレッド上で常に正常に実行する事が可能なコードを、スレッドセーフなコードと呼びます。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Q&A

解決済

2回答

10685閲覧

async/awaitの処理を行うスレッドについて

ibuki

総合スコア15

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

スレッドセーフ

マルチスレッド環境において、複数のスレッド上で常に正常に実行する事が可能なコードを、スレッドセーフなコードと呼びます。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

0グッド

2クリップ

投稿2018/03/05 10:06

編集2018/03/06 00:10

.NET Framework Windowsフォームアプリケーションにて、async/awaitで非同期の処理のテストプログラムを作成いたしました。
awaitの説明を読んで、非同期の処理を別スレッドで行い、完了したら元のスレッドに戻すと解釈したのですが、以下のGetintValueの中で止めて見てみると、元のメインスレッドで行われていました。
Task.Runのようにワーカースレッドで動くかと思っていたのですが、async/awaitの処理に対する解釈が間違っているでしょうか。

C#

1 int a; 2 private async void button_Click(object sender, EventArgs e) 3 { 4 while (true) 5 { 6 this.progressBar1.Value = await GetintValue(); 7 await Task.Run(() => 8 { 9 System.Threading.Thread.Sleep(1000); 10 }); 11 12 if (a >= 99) { a = 0; } 13 } 14 } 15 private async Task<int> GetintValue() 16 { 17 a++; 18 await Task.Delay(100); 19 return a; 20 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

まず第一にawaitに関する理解は大体は良いと思います。
通常は、実行後に元のスレッドに戻して処理を継続です。

しかし、awaitは別のスレッドを作ったりはしません。
他のスレッドで動かしたいなら、自分でスレッドは作る必要があります。
それがTask.Run等です。

次にasyncですが、これも別にスレッドをどうこうはしません。
ただawaitを使いますという宣言です。
なのでawaitを使わなければ gazette2さんの言う通りただの一般関数です。

そして戻り値のTask<int>ですが、これも別にスレッドをどうこうするものではないです。
これはint型の戻り値とTaskの状態が入っているだけです。
awaitはこのTaskの状態が完了になったら、元のスレッドで続行し、中のintを返すだけです。
Taskが別スレッドで動いたかは関係ないです。完了になったら終わるだけです。

csharp

1await Task.Delay(100); 2

このTask.Delayの中ではタイマーが呼び出されて、指定時間後にTaskの状態を完了に切り替える
動作をしています。タイマーは別スレッドです。
指定時間たつまでメインスレッドは暇です。なのでUIの更新等別の処理を行えます。
そして、Taskの状態が完了になったら、awaitはメインスレッドで
続きの処理(今回はreturn a;)を続行します。

追記(2018/03/06 12:08):
例えば今回のGetIntValueを別スレッドで実行するには、

csharp

1private async Task<int> GetintValue() 2{ 3 return await Task.Run(async () => 4 { 5 a++; 6 await Task.Delay(100); 7 return a; 8 }); 9}

このようにすることで別スレッドで実行されます。

投稿2018/03/06 02:08

編集2018/03/06 03:09
sh_akira

総合スコア380

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ibuki

2018/03/06 02:38

ご回答ありがとうございます。 awaitの、元スレッドに戻す前に別スレッドで処理を行っているというのを見ることはできないというよりは 非同期処理の動きを見るためには await Task.Delay(100); では、スレッドが空いてしまうので不適切という感じでしょうか。
sh_akira

2018/03/06 03:07

a++; await Task.Delay(100); return a; この3行の中のa++とreturn aは非同期ではありません。 Task.Delayの"中"のタイマー処理だけが非同期です。 そもそも"非"同期処理とは別のスレッドで実行するという事です。 回答に書いたように、例えばTask.Runを使うと、 private async Task<int> GetintValue() { return await Task.Run(async () => { a++; await Task.Delay(100); return a; }); } このように書けますので、それぞれa++;にブレイクポイントを打って、 スレッドを見ると違いが分かるかと思います。
sh_akira

2018/03/06 03:10

回答に見やすいコードを追記してますので、確認してください。
gazette2

2018/03/06 03:24

この答えのほうがもっと明確ですね。asyncキーワードは中にawaitがあると言う標識だと思えば理解しやすいかもしれません。
ibuki

2018/03/06 04:31

ありがとうございます。 a++部分でワーキングスレッドになっていること、 およびワーカースレッドで実行中もメインスレッドの処理を行えることを確認しました。 async/awaitでの非同期動作がイメージできたと思います。
guest

0

関数をasyncに指定しても関数の中でawaitが利用されない場合にはただの一般関数(Sync)になります。

要請に応じて追加します。

この場合は確かに非同期の処理されました
が、それをデバッガーで確認することができないだけです。
関数をasyncに指定してもその関数の全てがasyncになるわけではありません。
async関数はawaitが出現するところまではSyncモードで実行されます。

つまり

private async Task<int> GetintValue() { a++; await Task.Delay(100); return a; }

この関数の場合
a++;
return a;
はMainスレッドで処理されます。

そしてTask.Delay(100)の部分だけが別のスレッドで実行されます。
(もっと正確にはTask.Delay(100)の中のどこかでスレッドで実行される部分があります。sh_akiraさんの説明を参考)

しかし、普通のデバッガーの設定ではTask.Delay(100)の中身を見ることが出来ないので
スレッドは生成されましたがすぐ無くなってしまってそれが確認することが出来ない…
ということです。

なので、そのTask.Delay(100)の部分をこんな風に還ってテストしてみましょう。

private async Task<int> GetintValue() { // Sync int bbb = 0; // this code will be running on Main thread // Async int testValue = await Task.Run(() => { int a = 1; // this code will be running on the sperated thread a++; return a; }); return testValue; }

bbb = 0;
まではMainで実行されますがそのあと別のスレッドを作るのを確認できます。

投稿2018/03/05 11:32

編集2018/03/06 03:56
gazette2

総合スコア179

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ibuki

2018/03/06 00:09

お答えありがとうございます。 async 関数の中に await Task.Delay(100); を追加しましたが、やはりメインスレッドでした。 async/awaitで行っている別スレッド処理はデバッグモードで見ることはできないのでしょうか
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問