C#非同期処理ことはじめ

ようやくC#の非同期処理を使い始めたので、メモしておきます。



デスクトップアプリを作っているときに、ボタンを押して時間がかかる処理があると、処理が進んでいることを表示したいと云うことが多いと思います。

そこで、下記のようなコードを書くわけですが、実行すると、ラベルは「0」にも「1」にもならず、すべての処理が終わった後に「2」が表示されるという不本意な動作となります。

        private void button3_Click(object sender, EventArgs e)
        {
            var sql = "waitfor delay '00:00:05'";

            this.labelStatus.Text = "0";

            DataTable dt1 = mm40Database.doSqlQuery(sql);
            this.labelStatus.Text = "1";

            DataTable dt2 = mm40Database.doSqlQuery(sql);
            this.labelStatus.Text = "2";
        }

この場合、DoEventsメソッドを呼ぶというのが解決策のひとつでした。下記のようにすると、ラベルには「0」、「1」、「2」と順に表示されます。

        private void button2_Click(object sender, EventArgs e)
        {
            var sql = "waitfor delay '00:00:05'";

            this.labelStatus.Text = "0";
            Application.DoEvents();

            DataTable dt1 = mm40Database.doSqlQuery(sql);
            this.labelStatus.Text = "1";
            Application.DoEvents();

            DataTable dt2 = mm40Database.doSqlQuery(sql);
            this.labelStatus.Text = "2";
        }

別の解決策が非同期処理で、時間がかかる処理を非同期で実行してawaitで終了を待ちます。下記のように。

        async private void button1_Click(object sender, EventArgs e)
        {
            var sql = "waitfor delay '00:00:05'";

            this.labelStatus.Text = "0";

            DataTable dt1 = await Task<DataTable>.Run(() => mm40Database.doSqlQuery(sql));         // 非同期!
            this.labelStatus.Text = "1";

            DataTable dt2 = await Task<DataTable>.Run(() => mm40Database.doSqlQuery(sql));         // 非同期!
            this.labelStatus.Text = "2";
        }

DoEventsメソッドを呼ばなくてもラベルは「0」、「1」、「2」と表示されます。すごく自然でよいね。まあ、「await Task<Type>.Run(() => メソッド呼び出し)」が見慣れないコードで、すごく不自然かもしれない。

これはこういうものだと、今は思っておく。時間がかかるメソッド呼び出しを非同期にしたいときは、そこをこういう具合に書き換えると。

たぶん、ほとんどの場合は、この方法で対応できるのではないかな。

ラムダ式に慣れていないと訳が分からないわな。



コメント

このブログの人気の投稿

varchar をデータ型 numeric に変換中に、算術オーバーフロー エラーが発生しました。