C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[9]: BackgroundWokerの処理時間について


(過去ログ 83 を表示中)

[トピック内 11 記事 (1 - 11 表示)]  << 0 >>

■49480 / inTopicNo.1)  BackgroundWokerの処理時間について
  
□投稿者/ Kaze (2回)-(2010/05/06(Thu) 15:25:54)

分類:[.NET 全般] 

お世話になります。
WindowsXP SP3とVisualBasic Express Editionを使用しています。

.NET3.5のBackgroundWokerを使用して、動画処理の高速化を狙ってみましたが、逆に遅くなってしまいました。
目的は動画カメラから画像を取り込み、表示しながら画像を毎コマ静止画として保存することです。
動画カメラは15fpsの物を使用しています。

現在は
画像取得→画像表示(画像処理)→画像保存
と、なっており、画像表示と画像保存をBackgroundWokerで処理させて速度向上を狙ってみたのですが、逆に遅くなってしまいました。
(画像表示と画像保存が終了する前に次の画像取得をした場合、その画像は破棄しています)

処理速度をSystem.Environment.TickCountで計測したところ、
画像取得に50ms 画像表示10ms 画像保存10ms
程度の時間になっており、画像処理等で足を引っ張ってはいないと思われます。

BackgroundWokerはフレーム毎に細かい処理を行うのでは無く、大きな処理をまとめて分割するのに有効と思ってよろしいのでしょうか?
よろしくお願いします。
引用返信 編集キー/
■49481 / inTopicNo.2)  Re[1]: BackgroundWokerの処理時間について
□投稿者/ よねKEN (493回)-(2010/05/06(Thu) 16:10:33)
2010/05/06(Thu) 16:11:55 編集(投稿者)

No49480 (Kaze さん) に返信
> 現在は
> 画像取得→画像表示(画像処理)→画像保存
> と、なっており、画像表示と画像保存をBackgroundWokerで処理させて速度向上を狙ってみたのですが、逆に遅くなってしまいました。

遅くなったという判断はどのように考えた結果でしょうか?
BackgroundWokerを使わない状態ではどうで(何を問題視しているのか?)、
使った場合はどうなったのでしょうか?(また、どういう結果を期待していたのか?)
画像表示や画像保存というのが具体的にどういう処理を行っているのかという情報も必要ですね。

> 処理速度をSystem.Environment.TickCountで計測したところ、
> 画像取得に50ms 画像表示10ms 画像保存10ms
> 程度の時間になっており、画像処理等で足を引っ張ってはいないと思われます。

これは使った後の計測結果でしょうか?その場合、使う前との比較で示して頂かないと
結局のところ何を問題と思われているのかが理解できません。
上記の説明だけで見ると、画像取得 > 画像表示 + 画像保存 のため、
何の問題もないように思えますけど・・・
(「画像取得 > 画像表示 + 画像保存」なら次の画像取得までの間に画像表示も画像保存も終わるから)

> BackgroundWokerはフレーム毎に細かい処理を行うのでは無く、大きな処理をまとめて分割するのに有効と思ってよろしいのでしょうか?

UIスレッドで重い処理を実行すると、その間ユーザ操作を受け付けられなくなるため、
別スレッドで重い処理を実行するためにBackgroundWokerを使います。

並列処理としての効果を期待しているのであれば、ボトルネックを正しく把握する必要があります。
例えば、画像表示はUIスレッドとの同期が発生すると思いますので、
別スレッドで処理を行ったからといって性能向上が見込めるとは限りませんし、
画像保存はハードディスクへの書き込みの処理の比重が大きいでしょうから、
これも性能向上を見込めるかどうかは不明です。


引用返信 編集キー/
■49482 / inTopicNo.3)  Re[2]: BackgroundWokerの処理時間について
□投稿者/ よねKEN (494回)-(2010/05/06(Thu) 16:16:03)
2010/05/06(Thu) 16:18:56 編集(投稿者)

一部訂正です。

No49481 (よねKEN さん) に返信
>>処理速度をSystem.Environment.TickCountで計測したところ、
>>画像取得に50ms 画像表示10ms 画像保存10ms
>>程度の時間になっており、画像処理等で足を引っ張ってはいないと思われます。
>
> これは使った後の計測結果でしょうか?その場合、使う前との比較で示して頂かないと
> 結局のところ何を問題と思われているのかが理解できません。
> 上記の説明だけで見ると、画像取得 > 画像表示 + 画像保存 のため、
> 何の問題もないように思えますけど・・・

何の問題もない・・・は間違いですね。失礼しました。
15fpsということは、1000msで15枚処理しないといけないから、1枚当たりの持ち時間は、
66.6msくらいで、となると全部で70msだと足りないですね。

画像取得がボトルネックのようなので、こちらの処理こそ可能であれば、
別スレッドにした方がよいような気もしますが、
どんな処理なのかわからないのでもう少し情報がないと何とも言えないですね。
引用返信 編集キー/
■49484 / inTopicNo.4)  Re[2]: BackgroundWokerの処理時間について
□投稿者/ Kaze (3回)-(2010/05/06(Thu) 17:48:58)
早速の返信ありがとうございます。
情報足らずですいません。

> 遅くなったという判断はどのように考えた結果でしょうか?
> BackgroundWokerを使わない状態ではどうで(何を問題視しているのか?)、
> 使った場合はどうなったのでしょうか?(また、どういう結果を期待していたのか?)
> 画像表示や画像保存というのが具体的にどういう処理を行っているのかという情報も必要ですね。

出力された画像枚数を、全体の撮影時間で割っています。
これで、1秒辺りの保存枚数を増やすことを目的にしています。
現在は15fpsで画像取得だけで50ms使われている為、実際のところ12fps程度しか保存出来ていません。
画像取得以外をBackgroundWokerで並列に動かすことで、出来る限り15fpsに近づけ無いかと思って使用してみたところ、
7fpsにまで下がってしまったので、上記のような判断をしました。
(前回書き忘れていましたが、CPUは4コアのi7を使用しています)

画像はアナログカメラをデジタルに変換するコンバーターを使用しており、そのSDKを使用して取り込んでいます。
640×480のBitmap形式にて送られてくるので、先鋭化等の画像処理を行う為、UnLockBitsでバイト配列に変換しています。

画像表示は配列を再度Bitmapクラスに変換し、PictureBoxにDrawImageにて表示しています。
画像の保存はSaveメソッドにて保存しています。

>>処理速度をSystem.Environment.TickCountで計測したところ、
>>画像取得に50ms 画像表示10ms 画像保存10ms
>>程度の時間になっており、画像処理等で足を引っ張ってはいないと思われます。
>
> これは使った後の計測結果でしょうか?その場合、使う前との比較で示して頂かないと
> 結局のところ何を問題と思われているのかが理解できません。
> 上記の説明だけで見ると、画像取得 > 画像表示 + 画像保存 のため、
> 何の問題もないように思えますけど・・・
> (「画像取得 > 画像表示 + 画像保存」なら次の画像取得までの間に画像表示も画像保存も終わるから)

失礼しました。
これは使う前の計測結果です。
おっしゃる通り「画像取得 > 画像表示 + 画像保存」なので、画像表示と画像保存をBackgroundWokerで動かすことで、
ほぼ画像表示の時間だけで処理が出来ることを期待して使ってみました。

> UIスレッドで重い処理を実行すると、その間ユーザ操作を受け付けられなくなるため、
> 別スレッドで重い処理を実行するためにBackgroundWokerを使います。
>
> 並列処理としての効果を期待しているのであれば、ボトルネックを正しく把握する必要があります。
> 例えば、画像表示はUIスレッドとの同期が発生すると思いますので、
> 別スレッドで処理を行ったからといって性能向上が見込めるとは限りませんし、
> 画像保存はハードディスクへの書き込みの処理の比重が大きいでしょうから、
> これも性能向上を見込めるかどうかは不明です。

画像表示や画像保存は、開始から終了の時間が共に10ms程度だったので大丈夫と判断したのですが・・・間違っているのでしょうか?


> 何の問題もない・・・は間違いですね。失礼しました。
> 15fpsということは、1000msで15枚処理しないといけないから、1枚当たりの持ち時間は、
> 66.6msくらいで、となると全部で70msだと足りないですね。

> 画像取得がボトルネックのようなので、こちらの処理こそ可能であれば、
> 別スレッドにした方がよいような気もしますが、
> どんな処理なのかわからないのでもう少し情報がないと何とも言えないですね。

はい、全体だと微妙に足りないのです。
画像取得をBackgroundWokerにて動かしたところ、10fpsになりました。
だいぶ早くなりましたが、まだ使わない状態のほうが少し早いですね。
もう少し悩んでみます。
引用返信 編集キー/
■49487 / inTopicNo.5)  Re[3]: BackgroundWokerの処理時間について
□投稿者/ れい (910回)-(2010/05/06(Thu) 18:32:59)
マルチコア化しているとはいえ、
一般にスレッド切り替えやプロセス切り替えは重い処理ですので、単一スレッドの方がパフォーマンスは高くなります。
ユーザービリティが下がりますが。

また、15ftsくらいになると微妙ですが、
一般にGUI操作は単一スレッドで十分にパフォーマンスとユーザビリティを両立できます。

#それができるほど処理能力があがったからGUIなOSが存在できるわけなので、論理が逆ですが。

私もおそらく似たような装置を使っており、BackgroundWorkerも使っていますが、さらにキューを使っています。

Kazeさんの場合も最大パフォーマンスでぎりぎりですので、マルチコアなら間に合っているはずです。
画像取得、画像処理、画像保存をキューイングしてBackgroundWorkerで処理すれば15fps程度ならいけると思います。

めんどくさければ一番重い画像取得だけでもいいですね。

15fpsの画像全てをGUI上に表示しなければならない、ということはあまりないでしょうから、
画面表示はGUIスレッドが空いたときに更新、というのが普通かと思います。

引用返信 編集キー/
■49497 / inTopicNo.6)  Re[4]: BackgroundWokerの処理時間について
□投稿者/ kaze (4回)-(2010/05/06(Thu) 21:38:23)
> マルチコア化しているとはいえ、
> 一般にスレッド切り替えやプロセス切り替えは重い処理ですので、単一スレッドの方がパフォーマンスは高くなります。
> ユーザービリティが下がりますが。
>
> また、15ftsくらいになると微妙ですが、
> 一般にGUI操作は単一スレッドで十分にパフォーマンスとユーザビリティを両立できます。

なるほど、細目に切り替えるくらいなら無理にマルチスレッドを使う必要は無いのですね。

> 私もおそらく似たような装置を使っており、BackgroundWorkerも使っていますが、さらにキューを使っています。
>
> Kazeさんの場合も最大パフォーマンスでぎりぎりですので、マルチコアなら間に合っているはずです。
> 画像取得、画像処理、画像保存をキューイングしてBackgroundWorkerで処理すれば15fps程度ならいけると思います。
>
> めんどくさければ一番重い画像取得だけでもいいですね。

似たような環境なのは心強いです。
BackgroundWoker+キューですか。
そこまでは考えていなかったので、勉強になります。ありがとうございます。

> 15fpsの画像全てをGUI上に表示しなければならない、ということはあまりないでしょうから、
> 画面表示はGUIスレッドが空いたときに更新、というのが普通かと思います。

確かに15fpsをじっくり見ていても、目視では見ていられませんしね。
表示は4fps程度を目安にして、他のことに処理を回すようにしてみます。
引用返信 編集キー/
■49530 / inTopicNo.7)  Re[5]: BackgroundWokerの処理時間について
□投稿者/ 甕星 (9回)-(2010/05/07(Fri) 11:31:33)
マルチコアを活かしたアプリケーションの作りにするためには、画像を取得するスレッド、画像を保存するスレッド、画像を表示するスレッドをそれぞれ別のスレッドにして並列実行しなければ意味がありません。そうすることで、画像の取得と、画像の保存を、本当の意味で同時に実行できるのです。

スレッド1 1枚目画像取得 2枚目画像取得 3枚目画像取得
スレッド2         1枚目画像保存 2枚目画像保存
スレッド3         1枚目画像表示 2枚目画像表示

ちなみに時刻計測にTickCountを使っていますが、この関数は短い時間を計測できません。HELPには「TickCount プロパティの解像度は、500 ミリ秒未満には設定できません。」と書かれていますよね。OSレベルで10ms程度に丸められてしまうので、10ms単位での時間しか測れないんですよ。パフォーマンスカウンタを使うか、100回実行するのにかかる時間を測るとかしないと・・・。もし1回の時間を測って10msと言っているなら、それは10ms〜20msかかっていると言う事だと思います。

ファイルの保存と言うのは思っているよりも時間のかかる処理です。HDDのスペックシートに平均シークタイムとか回転数が書かれていますよね。読み書きしようとする場所にヘッドを移動するためにかかる時間ですが、普通に数msかかります。HDDに10ms以下で保存を完了すると言うのは、かなり高い要求です。数回ヘッドのシークが発生したら、それだけで時間オーバーになってしまいます。数十回の保存ならライトバックキャッシュに載るので大丈夫でしょうけど、長時間連続保存だと難しいです。
引用返信 編集キー/
■49545 / inTopicNo.8)  Re[6]: BackgroundWokerの処理時間について
□投稿者/ Kaze (4回)-(2010/05/08(Sat) 02:32:14)
> マルチコアを活かしたアプリケーションの作りにするためには、画像を取得するスレッド、画像を保存するスレッド、画像を表示するスレッドをそれぞれ別のスレッドにして並列実行しなければ意味がありません。そうすることで、画像の取得と、画像の保存を、本当の意味で同時に実行できるのです。
>
> スレッド1 1枚目画像取得 2枚目画像取得 3枚目画像取得
> スレッド2         1枚目画像保存 2枚目画像保存
> スレッド3         1枚目画像表示 2枚目画像表示

今のところ、タイマーの中で細かく何度もスレッドを呼び出すなんちゃってマルチスレッドになってます。
ちゃんとそれぞれのスレッドを独立させて処理させないといけないですよね・・・。

> ちなみに時刻計測にTickCountを使っていますが、この関数は短い時間を計測できません。HELPには「TickCount プロパティの解像度は、500 ミリ秒未満には設定できません。」と書かれていますよね。OSレベルで10ms程度に丸められてしまうので、10ms単位での時間しか測れないんですよ。パフォーマンスカウンタを使うか、100回実行するのにかかる時間を測るとかしないと・・・。もし1回の時間を測って10msと言っているなら、それは10ms〜20msかかっていると言う事だと思います。

TickCountはやめて、Stopwatchを使うように変更しました。
出てくる表示はあまり変わらないので、TickCountも比較的正確だったのかも。

> ファイルの保存と言うのは思っているよりも時間のかかる処理です。HDDのスペックシートに平均シークタイムとか回転数が書かれていますよね。読み書きしようとする場所にヘッドを移動するためにかかる時間ですが、普通に数msかかります。HDDに10ms以下で保存を完了すると言うのは、かなり高い要求です。数回ヘッドのシークが発生したら、それだけで時間オーバーになってしまいます。数十回の保存ならライトバックキャッシュに載るので大丈夫でしょうけど、長時間連続保存だと難しいです。

画像取得のBackgroundWorkerと、画像表示&保存のBackgroundWorkerを用意して、
取得した画像をキューに入れ、表示&保存でキューから取り出して表示と保存を行うことで、
ほぼ秒15枚を実現することが出来ました。
皆様ありがとうございます。

ただ、重い画像処理を行うと、画像が崩れるのは・・・自分のプログラムミスでしょうね。
表示側のバックグラウンドはBackgroundWorker.IsBusyで処理中ならパスするようにし、
取得数>表示&保存数の時だけ実行するようにしているのですが。

二つのバックグラウンドにグローバル宣言した一つのキューを使用するのは問題無いですよね?

引用返信 編集キー/
■49546 / inTopicNo.9)  Re[7]: BackgroundWokerの処理時間について
□投稿者/ 渋木宏明(ひどり) (1325回)-(2010/05/08(Sat) 03:45:43)
渋木宏明(ひどり) さんの Web サイト
> 画像取得のBackgroundWorkerと、画像表示&保存のBackgroundWorkerを用意して、
> 取得した画像をキューに入れ、表示&保存でキューから取り出して表示と保存を行うことで、
> ほぼ秒15枚を実現することが出来ました。

今時のPCなら、もう少しイケそうな気が。

キューが空の時、無駄に BackgroundWorker が実行され(キューをポーリングするなど)てたりしていませんか?
もしそうなら、そこら辺を同期オブジェクトを使うなどして無駄な実行を排除するようにすれば、もう少し性能が出るかもしれません。

> ただ、重い画像処理を行うと、画像が崩れるのは・・・自分のプログラムミスでしょうね。

崩れるのは表示ですか?それともファイル保存した画像?

> 表示側のバックグラウンドはBackgroundWorker.IsBusyで処理中ならパスするようにし、
> 取得数>表示&保存数の時だけ実行するようにしているのですが。

ここも無駄なポーリングが潜んでそうな予感。
ファイル保存のキュートは別系統で、表示用のビットマップを保持する仕掛けを作った方が効率的な気がします。

> 二つのバックグラウンドにグローバル宣言した一つのキューを使用するのは問題無いですよね?

問題ないけど、グローバルである必要も特に無いですね。
画像取り込みとファイル保存、それぞれの BackgroundWorker から見えるところにキューがあればいいだけです。

引用返信 編集キー/
■49564 / inTopicNo.10)  Re[8]: BackgroundWokerの処理時間について
□投稿者/ kaze (6回)-(2010/05/09(Sun) 11:33:31)
> 今時のPCなら、もう少しイケそうな気が。
>
> キューが空の時、無駄に BackgroundWorker が実行され(キューをポーリングするなど)てたりしていませんか?
> もしそうなら、そこら辺を同期オブジェクトを使うなどして無駄な実行を排除するようにすれば、もう少し性能が出るかもしれません。

タイマー制御で10ms,33ms,66ms毎にBackgroundWorkerを実行したり、BackgroundWorkerの中で取り込みと保存をループさせてみたりしてみましたが、処理時間はほとんど変わりませんでした。
66msならほぼ1対1ですが、10msだと6倍実行されるからポーリング過多になるかなと思いましたが、この認識で合っていますでしょうか?
ついでにngenも使用してみましたが、やっぱり変わりませんでした。

> 崩れるのは表示ですか?それともファイル保存した画像?
崩れるのは両方ですね。
画像処理が1種類なら良いのですが、複数を組み合わせると崩れることから、その間に問題があるのかなと調査しています。

> ここも無駄なポーリングが潜んでそうな予感。
> ファイル保存のキュートは別系統で、表示用のビットマップを保持する仕掛けを作った方が効率的な気がします。

表示と保存を別のバックグラウンドで処理するようにしてみました。
今までは重い処理を行うと表示用のキューがどんどん溜まってたのですが、それが無くなったので効率はかなり良くなりました。
ところで、Bitmap型をそのままキューに入れる方法ってあるのでしょうか?

> 問題ないけど、グローバルである必要も特に無いですね。
> 画像取り込みとファイル保存、それぞれの BackgroundWorker から見えるところにキューがあればいいだけです。
確かに、あんまり広くても意味ありませでしたね。

いろいろ指摘して頂き、ありがとうございます。
引用返信 編集キー/
■49565 / inTopicNo.11)  Re[9]: BackgroundWokerの処理時間について
□投稿者/ 渋木宏明(ひどり) (1326回)-(2010/05/09(Sun) 13:24:14)
渋木宏明(ひどり) さんの Web サイト
>この認識で合っていますでしょうか?

ちょっと話が噛みあっていないかもしれません。

現状、「『キューに項目が投入されたこと』を検知するためにポーリング」しているのであれば、それに替えて「『同期オブジェクト』によって『キューに項目が投入されたこと』を伝達する」方が、無駄な CPU 消費を低減でき、性能向上出来る可能性があるのではないか、ということです。

>>崩れるのは表示ですか?それともファイル保存した画像?
> 崩れるのは両方ですね。
> 画像処理が1種類なら良いのですが、複数を組み合わせると崩れることから、その間に問題があるのかなと調査しています。

画像処理自体に問題があるのか、画像処理を行うために使用しているメモリの管理に問題があるのかの切り分けが必要ですね。

> ところで、Bitmap型をそのままキューに入れる方法ってあるのでしょうか?

Queue<T> なら何でも入りますよ。

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -