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

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

ただいまの
回答率

90.48%

  • C#

    9213questions

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

  • 非同期処理

    138questions

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

  • スレッドセーフ

    15questions

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

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

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 3,157

ibuki

score 9

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

        int a;
        private async void button_Click(object sender, EventArgs e)
        {
            while (true)
            {
                this.progressBar1.Value = await GetintValue();
                await Task.Run(() =>
                {
                   System.Threading.Thread.Sleep(1000);
                });

                if (a >= 99) { a = 0; }
            }
        }
        private async Task<int> GetintValue()
        {
            a++;
            await Task.Delay(100);
            return a;
        }
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+5

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

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

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

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

await Task.Delay(100);


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

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

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


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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/06 11:38

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

    キャンセル

  • 2018/03/06 12: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++;にブレイクポイントを打って、
    スレッドを見ると違いが分かるかと思います。

    キャンセル

  • 2018/03/06 12:10

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

    キャンセル

  • 2018/03/06 12:24

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

    キャンセル

  • 2018/03/06 13:31

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

    キャンセル

+4

関数を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/06 09:09

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

    キャンセル

同じタグがついた質問を見る

  • C#

    9213questions

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

  • 非同期処理

    138questions

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

  • スレッドセーフ

    15questions

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