2012年12月01日
.NET Framework4.5 での非同期I/O処理 事始め
この記事は、C# Advent Calender 2012 http://atnd.org/events/33905 への参加記事です。
今年もC# Advent Calender が開始されました。
なかなか書くネタが見つからず、参加しようかどうか悩んでいるうちに、気が付いたら、空いている日が、
初日の 12/1 と 最終日の 12/25 の2日だけになってました。さすがに最終日はプレッシャーがかかると
思ったので、初日である 12/1 にエントリーさせてもらいました。
さて、お題は、「.NET Framework4.5 での非同期I/O処理 事始め」です。
既に多くの方がブログで async, awaitの記事を書いているので、2番煎じ、3番煎じの感は
否めませんが、まあ、このC# Advent Calenderは、ゆるいイベントということなので、大目
に見てください(^^;
さて、ここからが本題です。
.NET Framework4.5から、非同期IOをサポートする新しいasync系メソッドが追加されています。
これにより、従来よりもより簡単に非同期IO処理が書けるようになりました。
■.NET Framework4.0 以前の非同期I/O処理
まずは、.NET Framework4.0 以前はどうだったかを振り返ってみましょう。
これまでの Streamクラスには、BeginRead, EndRead といった非同期IOをサポートするメソッドが
用意されていました。
従来の非同期IOの簡単なサンプルを以下に示します。
このコードは、Sample.txtファイルを非同期IOで読み込み、TextBox にその内容を表示しています。
※ 今回は、WindowsFormsを使いましたが、WPFでもなんら変わることはありません。
ファイルのサイズが小さければ、こんな面倒なコードを書かずに、File.ReadAllTextで一気に
読み込んでしまって良いと思いますが、巨大なファイルの場合は、UIがフリーズするのを防止できません。
UIのフリーズを防止するには、スレッドを起動するとか、BackgroundWorkerクラスを利用するとか、Taskを使うとか、
いろいろと方法はありますが、同期処理に比べると面倒です。
それと、上記のコードは、テキストファイルを扱うのに、ReadLine系のメソッドを使えないため、byte配列に
読み込んでいて、いまいち感がぬぐえません。
■.NET Framework4.5 での非同期I/O処理
では、C#5.0 + .NET Framework4.5ではどうなるかを見てみましょう。
上記コードの注目点は、以下の4点です。
1. メソッドに、async キーワードが付いている。
2. ReadLineAsync() という非同期IOメソッドを使っている。
3. この非同期IOメソッドに、await キーワードをつけている。
4. 同期処理のように、UIへのアクセスを普通に行っている。
メソッドに、await キーワードを使う場合には、必ずメソッドにasync キーワードをつける必要があります。
そして、await を使うことで、非同期処理をあたかも同期処理のように書くことが
可能になります。
いやー、これはほんとうに便利ですね。
■IProgressによるロジックとUIの分離
でも、ファイルIO処理の中で、UIにアクセスするコードを書くのは嫌だ! と思う人も多いと思います。
大丈夫です。.NET Framework4.5では、そういった要求にも簡単にこたえることができます。
コードを示します。
ReadTextDataメソッドの引数に、Progress
このProgress
ここで、UI処理を書くわけですね。
ReadTextData メソッドの中では、progress.Report(s) と、Reportメソッドを呼び出しています。
このタイミングで、先ほどのコールバックが呼び出されることになります。
これで、ReadTextDataメソッドは、完全にUIとは分離されたので、Formクラスに書く必要もなくなりましたね。
Write系のコードも載せようと思ったのですが、まあ、上記とほとんど同じ感覚で書けるので、
あえて載せる必要もないでしょう。
2012年08月25日
ThreadStatic
staticフィールドは、複数のスレッドで共有されるので、
スレッド間で情報を共有する際に利用できますが、
スレッド毎に独立したstaticフィールドを持ちたい場合があります。
そんな時に、フィールドに ThreadStatic属性を使います。
しばらくぶりに、このThreadStatic属性を使いました。
あまりにもしばらくぶりだったので、その存在自体忘れてました(^^;
スレッド間で情報を共有する際に利用できますが、
スレッド毎に独立したstaticフィールドを持ちたい場合があります。
そんな時に、フィールドに ThreadStatic属性を使います。
しばらくぶりに、このThreadStatic属性を使いました。
あまりにもしばらくぶりだったので、その存在自体忘れてました(^^;
2009年08月09日
BackgroundWorkerのサンプルコード(4)
BackgroundWorkerのサンプルコード(1)
BackgroundWorkerのサンプルコード(2)
BackgroundWorkerのサンプルコード(3)
BackgroundWorkerのサンプルコード(3)で掲載したコードとほとんど同じだけど、バックグラウンド処理の結果を受け取れるようにしました。
終了していないのに、結果を取得しようとした場合は、終了するまで待つようにしてあります。
ついでにExecuteメソッドでは、引数を渡せるようにしてあります。
同期するために利用していたManualResetEventですが、代わりにAutoResetEventを使ってみました。
BackgroundWorkerのサンプルコード(2)
BackgroundWorkerのサンプルコード(3)
BackgroundWorkerのサンプルコード(3)で掲載したコードとほとんど同じだけど、バックグラウンド処理の結果を受け取れるようにしました。
終了していないのに、結果を取得しようとした場合は、終了するまで待つようにしてあります。
ついでにExecuteメソッドでは、引数を渡せるようにしてあります。
同期するために利用していたManualResetEventですが、代わりにAutoResetEventを使ってみました。
2009年08月06日
BackgroundWorkerのサンプルコード(3)
BackgroundWorkerのサンプルコード(1)
BackgroundWorkerのサンプルコード(2)
BackgroundWorkerは、Formが無くたって使えます。
今回のサンプルコードは、ManualResetEventを使って、終了まで待てるようにしています。
クラスMyWorkerをもうちょっと汎用的にしたいところですが、BackgroundWorkerの サンプルを示すことが目的なので、これで良しとします。
このプログラムを実行してみればわかりますが、worker1とworker2がパラレルに実行されているのが確認できます。
BackgroundWorkerのサンプルコード(2)
BackgroundWorkerは、Formが無くたって使えます。
今回のサンプルコードは、ManualResetEventを使って、終了まで待てるようにしています。
クラスMyWorkerをもうちょっと汎用的にしたいところですが、BackgroundWorkerの サンプルを示すことが目的なので、これで良しとします。
このプログラムを実行してみればわかりますが、worker1とworker2がパラレルに実行されているのが確認できます。
2009年08月02日
BackgroundWorkerのサンプルコード(2)
BackgroundWorkerのサンプルコード(1)
今度は、処理の進行状況をプログレスバーで表示する例です。
途中で、処理をキャンセルする例にもなっています。
Form1のボタンをクリックすると、Form2が開き、処理を開始します。
処理の進行状況は、プログレスバーで表示され、処理が終わると 自動的にForm2が閉じるというものです。
Form2には、キャンセルボタンが配置されていて、キャンセルボタンを押すと 処理を中止します。
今度は、処理の進行状況をプログレスバーで表示する例です。
途中で、処理をキャンセルする例にもなっています。
Form1のボタンをクリックすると、Form2が開き、処理を開始します。
処理の進行状況は、プログレスバーで表示され、処理が終わると 自動的にForm2が閉じるというものです。
Form2には、キャンセルボタンが配置されていて、キャンセルボタンを押すと 処理を中止します。
2009年07月29日
BackgroundWorkerのサンプルコード(1)
BackgroundWorkerで検索して、このブログに来ている人が結構いるようなので、何回かに分けて、BackgroundWorkerを使ったサンプルを載せたいと思います。
まずは、バックグラウンド処理で得られたデータをListBoxに順に表示する例です。
ついでに、ListBoxの自動スクロールもやってます。
当然、ListBoxに項目を追加している間でも、ListBoxの操作(選択など)が可能です。
まずは、バックグラウンド処理で得られたデータをListBoxに順に表示する例です。
ついでに、ListBoxの自動スクロールもやってます。
当然、ListBoxに項目を追加している間でも、ListBoxの操作(選択など)が可能です。