2012年12月01日

.NET Framework4.5 での非同期I/O処理 事始め

   このエントリーをはてなブックマークに追加 Clip to Evernote

この記事は、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系のコードも載せようと思ったのですが、まあ、上記とほとんど同じ感覚で書けるので、
あえて載せる必要もないでしょう。

  

Posted by gushwell at 10:30Comments(0)TrackBack(0)

2012年08月25日

ThreadStatic

   このエントリーをはてなブックマークに追加 Clip to Evernote
staticフィールドは、複数のスレッドで共有されるので、
スレッド間で情報を共有する際に利用できますが、
スレッド毎に独立したstaticフィールドを持ちたい場合があります。

そんな時に、フィールドに ThreadStatic属性を使います。
しばらくぶりに、このThreadStatic属性を使いました。
あまりにもしばらくぶりだったので、その存在自体忘れてました(^^;
  
Posted by gushwell at 14:41Comments(0)TrackBack(0)

2009年08月09日

BackgroundWorkerのサンプルコード(4)

   このエントリーをはてなブックマークに追加 Clip to Evernote
BackgroundWorkerのサンプルコード(1)
BackgroundWorkerのサンプルコード(2)
BackgroundWorkerのサンプルコード(3)

BackgroundWorkerのサンプルコード(3)で掲載したコードとほとんど同じだけど、バックグラウンド処理の結果を受け取れるようにしました。
終了していないのに、結果を取得しようとした場合は、終了するまで待つようにしてあります。
ついでにExecuteメソッドでは、引数を渡せるようにしてあります。
同期するために利用していたManualResetEventですが、代わりにAutoResetEventを使ってみました。


  
Posted by gushwell at 22:39Comments(0)TrackBack(0)

2009年08月06日

BackgroundWorkerのサンプルコード(3)

   このエントリーをはてなブックマークに追加 Clip to Evernote
BackgroundWorkerのサンプルコード(1)
BackgroundWorkerのサンプルコード(2)


BackgroundWorkerは、Formが無くたって使えます。
今回のサンプルコードは、ManualResetEventを使って、終了まで待てるようにしています。
クラスMyWorkerをもうちょっと汎用的にしたいところですが、BackgroundWorkerの サンプルを示すことが目的なので、これで良しとします。

このプログラムを実行してみればわかりますが、worker1とworker2がパラレルに実行されているのが確認できます。

  
Posted by gushwell at 22:54Comments(0)TrackBack(0)

2009年08月02日

BackgroundWorkerのサンプルコード(2)

   このエントリーをはてなブックマークに追加 Clip to Evernote
BackgroundWorkerのサンプルコード(1)

今度は、処理の進行状況をプログレスバーで表示する例です。
途中で、処理をキャンセルする例にもなっています。

Form1のボタンをクリックすると、Form2が開き、処理を開始します。
処理の進行状況は、プログレスバーで表示され、処理が終わると 自動的にForm2が閉じるというものです。
Form2には、キャンセルボタンが配置されていて、キャンセルボタンを押すと 処理を中止します。




  
Posted by gushwell at 23:29Comments(0)TrackBack(0)

2009年07月29日

BackgroundWorkerのサンプルコード(1)

   このエントリーをはてなブックマークに追加 Clip to Evernote
BackgroundWorkerで検索して、このブログに来ている人が結構いるようなので、何回かに分けて、BackgroundWorkerを使ったサンプルを載せたいと思います。

まずは、バックグラウンド処理で得られたデータをListBoxに順に表示する例です。
ついでに、ListBoxの自動スクロールもやってます。

当然、ListBoxに項目を追加している間でも、ListBoxの操作(選択など)が可能です。


  
Posted by gushwell at 23:53Comments(0)TrackBack(0)

2009年07月01日

AutoResetEvent の簡単なサンプル

   このエントリーをはてなブックマークに追加 Clip to Evernote
AutoResetEvent の簡単なサンプルです。

ManualResetEvent の簡単なサンプルと見比べてみると、その違いがわかります。

  
Posted by gushwell at 23:15Comments(0)TrackBack(0)

2009年06月30日

ManualResetEvent の簡単なサンプル

   このエントリーをはてなブックマークに追加 Clip to Evernote
ManualResetEvent の簡単なサンプルです。


button2をクリックすることで、ThreadProc内の処理が進みます。
  
Posted by gushwell at 22:48Comments(0)TrackBack(0)