- PR -

c# 高速化についての質問

投稿者投稿内容
葉瀬崎浩樹
大ベテラン
会議室デビュー日: 2005/06/28
投稿数: 115
お住まい・勤務地: 兵庫県
投稿日時: 2005-10-18 21:23
正直なところ、Tips的な高速化技術にはあまり興味が無いのです。
そのため詳しい解説はしませんでした。
先の投稿が中途半端になっているのは、半ば意図的です。
申し訳ありません。m(* ..)m

引用:

刹那さんの書き込み (2005-10-18 19:26) より:
isよりasでキャスト(無知なものでよくわかりません…汗 int i = (int)o;が(明示的)キャストではないのですか?


これは、完全に言葉足らずでした。
is演算子によって型チェックを行ってから、
キャストを実行するケースがありますよね。
このとき、as演算子でキャストしたほうが早い場合がある
ということです。
asを使ったキャストが有効なケースが、
たまにある、という程度にとらえてください。

引用:
エラーチェック より 例外処理(これはエラーチェックを多数かけるよりも例外処理で飛ばしてやるほうが早いという意味でしょうか?VB時代に防ぐことが可能なエラーは防ぐほうが良いとどこかで聞いた気がするのですが、c#ではエラーチェックを行うよりもエラーを発生させて拾うほうが良いのでしょうか?


えっと、例え話をしてみます。
あなたは、パソコンショップの店員さんです。
ある日あなたは、パソコンのパーツを1万個仕入れました。
1つのパーツが不良品かどうかをチェックするには、10秒かかります。
チェックをせずにお客さんに売る場合、
万一そのパーツに問題が発生したら、
そのパーツの交換に1日費やす必要があります。
但し、仕入れたパーツに不良品が含まれる確率は1万分の1です。

さて、ここで2択問題です。
・全てのパーツをチェックする方法
・問題が発生してから対処する方法
どちらの方法が時間コスト面において合理的でしょうか?
また、
・1回のチェックに要する時間
・パーツの個数
・不良品の確率
・不良品を売ってしまった場合の復旧コスト
等を変えた場合について、考えてみてください。
3番目の選択肢が無いかも考えてみてください。


えっと、ここからはパフォーマンスに関する個人的な考えを。
実行速度の高速化テクニックは、車のパーツ(例えばエンジン)を
高性能にするようなものだと思います。
高性能なエンジンを積んだからといって、車が早く目的地に着くとは限りません。
タイヤ・シャフト・シャーシ・ガソリン・オイル・ウィング等の要素が
効率的に連動しなくては、車は速くなりません。
さらにいうと、速い車が、常に早く目的地に着くとは限りません。
道路のコンディション、混雑具合、天候といった要素まで考えなくてはいけません。

いきなり速い車を作ろうとせずに、
遅いと感じるところを直しやすく作っておくのも、
高速化のための布石として、有効かと思います。
車が、エンジンやタイヤを交換することで速くなり、
パソコンが、CPUを変えたり、メモリを増やしたりで速くなるは、
そのように部品が交換可能になっているからです。
絶対的な速さを目的にされませぬように。
#そんなこと分っているよ!ということでしたらご容赦下さい。

参考書籍
CODE COMPLETE 下:第24章〜26章:一般的なパフォーマンスに関して
プログラミング.NETFramework:.NETフレームワークの仕組み
笊頭刹那
ベテラン
会議室デビュー日: 2005/10/17
投稿数: 55
お住まい・勤務地: オーストラリア
投稿日時: 2005-10-18 21:47
>なちゃさま
とくに現在では問題がないのですが、毎回プログラムを組むときに
「こここう組んだほうがいいのか?それともこうかな?人間に分かりやすくても速度に問題が出るなら、この程度のことなら…」など普段から考えているのでこの際思い切って質問してみようと思って質問しただけなので…どの程度を望むというわけではないのです、分かりにくくてすいません。

>todoさま
情報提供ありがとうございます、サラ読みしましたがASPのほうじっくり読んでみる必要ありますね

>甕星さま
引用:
コンパイル時の最適化を行っていなかった場合には影響するかもしれない。でも最適化した場合には、影響は排除されるはず。
素直にコンパイラが解釈すると、Settings.Tab.Locationと言うのは、(Settingのアドレス) + (TABへのOFFSET値) + (Location へのOFFSET値)となるはず。後半二つのOFFSET値の計算結果は変わらないので、最適化時に事前演算されて変わらなくなるはず。


なるほど、そういうことなら速度に関してはstructの入れ子を行っても大丈夫そうですね。

引用:
static に宣言した方が高速に動作するはずです。通常のメンバ関数はクラスのインスタンスを識別するための情報を何らかの形で(おろらく暗黙の引数として)渡しているはずです。staticに宣言すれば、その分確実に早くなるはずです。
・・・けどね、関数に渡されるパラメタが一つ減った程度の速度の改善は、よほど繰り返し呼び出すのでない限り、誤差と大差ありません。下手に使えばコードを分かりにくくするだけですので、高速化を目的としてstaticにする事は無いでしょう。


ちょうど先ほど紹介してもらった.NET Generalに乗っていました。0.7ns〜0.8nsほどの差が出るらしいです。ちなみにvirtual interfaceを使用した際には使用しなかった場合と5.2ns(virtual)5.3ns(interface)ほど差が出るらしいです、nなので体感速度は変わらないでしょうがかなり差が出てますね(ちなみにここで使った値は信用しないでほしいそうです)

引用:
C#言語仕様の「クラスと構造体の違い」を参照してください。
クラスでは単純に代入した場合に参照が渡されるのに対して、構造体では値のコピーが渡されます。代入のたびにインスタンスが複製されるので、通常は構造体の方が遅くなります。


と、言うことは承知しています、参照型と値型ですよね?参照型はアドレスが渡され値型は複製される。新規インスタンスを作成する場合は値型の方が高速と聞きましたが、それは値型のサイズが小さいからですかね?
で、このことから考えると
コード:
Point ptZeroZero = new Point(0,0);
Something(ptZeroZero);
void Someghint(Point pt)
{
---
}


とやると
ptZeroZeroとSomeghingのptと二つ値がコピーされる
コード:
Someghing(new Point(0,0));
省略


とするとSomeghintのptだけに値が渡される

よって毎回インスタンスを作成して指定したほうがいいということですか?

引用:

昔「一瞬と刹那の考察」と言う掲示板がありまして、それこそ1クロック単位での高速化についての解説がありました。もちろんアセンブラですけどね。とても楽しく読ませていただいたのを覚えています。でも、本当に高速化を目指すのなら、structとか、staticとか、usingとか、そんなミクロな視点でほんの僅かな高速化を重ねる前にやることがあるでしょう。アルゴリズムを見直すとか、データ構造(キャッシュヒット率に大きく影響する)を見直すとか、処理の並列化(ハイパースレッディングやマルチコアのCPUでは大きく影響する)を試みるとか、そもそも使用する言語の選択を見直すとか。


偶然にも僕の名前が入ってますね(笑。そもそも、今回「あまりにも遅くてたまらない助けてください」という意味のスレッドではなく、普段からプログラムを組むときに
「ここ、どっちのほうが早いんだろうか?」や「これとこれを使用した際のデメリットはいったいなんだろうか?」という小さな(ソフトウェアの問題とはほとんど関係ない)問題がずっと積み重なっていたので今作っているソフトを高速化することも含めて思い切って聞いてみようということで書き込んだスレッドなので、見直すものがないんですよ、もちろん高速化が必要になったときはアルゴリズムやデータ構造、処理の並列化については見直しています(と、いうかその手の高速化については解説が多数あるので困らない)使用する言語については…c++ですか、vb->c#と楽な言語に慣れるとc++の複雑さについていけないんですよね、いつかは学習したいと思ってはいるのですが、いまはまだ時期じゃないです。

ちょっと、勘違いされているみたいなので

いま行っていることがタブ型ランチャーを作成しているのでウィンドウが多数表示されます、コントロールはタイマーコントロールが3つにコンテキストメニューが1つのみの質素なつくりです(コントロール数が多くなるとインスタンス化に影響する…はず?)このウィンドウを大量に(といっても多くて五六個かと)表示するときにソフトが重くなったら嫌だなぁ…たくさんインスタンス化するんだから、フォームのコード数を減らしたほうがいいのかな(フォームのコード数がインスタンス化に影響するもんだと思っているのですが影響し…ますよね?自信なし)、いや、減らさなくてもサブルーチンをstaticにしてみたらどうだろうか?静的なのだからインスタンス化に関係ないんじゃないだろうか?早くなるかな?などということと、今までの疑問の積み重ねからいろいろと質問させていただきました、とくに現在処理の高速化をしなくちゃ使い物にならないわけじゃないんです、未来系でインスタンス化の速度向上をめざしているんです(といっても、高速化について知りたいというのは必要だからではなく知的好奇心からですが)すいません(汗。

ちなみにこういう細かな高速化の技もやってて楽しいんですがね、知的好奇心を満たす上で(その前に使えるソフト作れと言われそうだが…orz
笊頭刹那
ベテラン
会議室デビュー日: 2005/10/17
投稿数: 55
お住まい・勤務地: オーストラリア
投稿日時: 2005-10-18 21:55
被った…orz

>葉瀬崎浩樹さま

asのほうが早くなる場合がある…なんかマイクロソフトらしい設計ですねorz

エラーチェックと高速化の話楽しく読ませていただきました(*^^)
高速化については全レスでも言ったとおり現在問題になっているわけではなくただの知的好奇心に近いものがあるので大丈夫です、問題が発生した場合は大きなところから行きます(というか問題が発生したばあいにusingやstructなどの小さなところに目は行かないです)直しやすく作るという点でも、コメントと#regionが大好きな人間なのでコードの見易さはちょっと自身あります(笑。コードファイルの重さも自信ありますがorz

エラー処理に関しては事前にどのようなエラーがどの程度の割合で起こるか予測することが不可能なので、やはり拾えるエラーはすべて拾ってからのほうが良いと僕は考えます(ユーザー親切という面からも)まぁ、「すべて」は辛いですから、大きなものだけ拾ってますが(汗笑
iStation
大ベテラン
会議室デビュー日: 2003/12/08
投稿数: 158
投稿日時: 2005-10-18 22:04
HPCの領域なら...(個人的には大変関心があるのですが)

DAT301 High Performance Computing with the Windows Server Compute Cluster Solution
http://commnet.microsoftpdc.com/content/downloads.aspx

並列処理のリモートオブジェクトのホスティングにWindowsサービスを使っている方もおられますね。
WindowsでささやかにPCクラスタリングしよう
http://www2.itc.nagoya-u.ac.jp/pub/pdf/pdf/vol03_03/194_225kouza.pdf
_________________
IEEE-CSDP 2004-2007
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2005-10-19 23:21
引用:

「ここ、どっちのほうが早いんだろうか?」や「これとこれを使用した際のデメリットはいったいなんだろうか?」という小さな(ソフトウェアの問題とはほとんど関係ない)問題がずっと積み重なっていたので今作っているソフトを高速化することも含めて思い切って聞いてみようということで書き込んだスレッドなので、見直すものがないんですよ


という事なので、ちょっと偉そうに Tips。

struct の話をされていますが、
コード:

Point ptZeroZero = new Point(0,0);
Something1(ptZeroZero);
Something2(ptZeroZero);


こうするのと、
コード:

Something1(new Point(0,0));
Something2(new Point(0,0));


こうするの、どっちがいい?って事かと思ったのですが。
速度、効率で言えば前者に分がありますね。何故かは分かるでしょう。

引用:

コード:

Point ptZeroZero = new Point(0,0);
Something(ptZeroZero);
void Someghint(Point pt)
{
---
}


とやると
ptZeroZeroとSomeghingのptと二つ値がコピーされる
コード:

Someghing(new Point(0,0));
省略


とするとSomeghintのptだけに値が渡される

よって毎回インスタンスを作成して指定したほうがいいということですか?


違うんじゃないかな。(多分)
この場合は一緒。Something が呼ばれる寸前に、どちらも一旦スタックに保存され、メソッドを呼び出し、引数にコピーしています。

あと struct に関しては、ボクシング、ボクシング解除が頻発するとパフォーマンスが下がってしまいます。(気づかない間にボクシングされているかもね)自分で作る型に関してはほぼ class で事足るでしょうし、「struct だと非常に便利!」という理由がない限り、取り敢えず struct は避ける方向のほうが良さそうです。

配列のアクセス等も
コード:

for( int i = 0; i < 100; i++ )
{
x[ i ] = y[ i ] + z[ i ];
Function( x[ i ], y[ i ], z[ i ] );
Console.WriteLine( x[ i ].ToString(), y[ i ].ToString(), z[ i ].ToString() );
}


とするより、
コード:

for( int i = 0; i < 100; i++ )
{
ObjX x = x[ i ];
ObjY y = y[ i ];
ObjZ z = z[ i ];

x = y + z;
Function( x, y, z );
Console.WriteLine( x.ToString(), y.ToString(), z.ToString() );
}


とした方が良いとか。これはご存知かもしれませんね。
理由はお察しの通りw。
それに加えて、インデックスアクセスは CLR 特有のチェックが入りますからね。

is as のキャストの話は、実は is は2回 CLR が型チェックするから。
つまり、
コード:

if( o is Obj1 ) -- @
{
Obj1 ob = (Obj1)o; -- A
}


コード:

Obj1 ob = o as Obj1; -- @
if( ob != null)
{

}


なので、正確には「as の方が速いではなく」「is を使うと2回チェックせざる得ないので遅い」ですね。
#編集
(あ、葉瀬崎浩樹さんが書いている事ですね。失礼しました。)

他にも何かあるかもしれませんが、今パッと出てきません。
結構どうでも良い事書いてみました^^;

細かいパフォーマンスに関しては皆さんと同意見。結構どうでもいいですね^^;。
けれども、普段コードを書いているとき、ちょっと気をつける、という事に関しては賛成です。


[ メッセージ編集済み 編集者: 囚人 編集日時 2005-10-19 23:27 ]
karajan
ベテラン
会議室デビュー日: 2002/07/05
投稿数: 89
投稿日時: 2005-10-20 00:12
C#というわけではありませんが、.NETアプリを構築の際にどの局面でどのクラスを使うべきかみたいなことであれば、
Improving .NET Application Performance and Scalability
という本があります。多分日本語訳は出ないであろうとのことですが、もし英語が苦手でなければリファレンス的な読み方もできますので、手元においておくのもいいかもしれません。
1000ページあり、値段も安くはありませんが、参考までに・・・。

[ メッセージ編集済み 編集者: karajan 編集日時 2005-10-20 00:13 ]
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2005-10-20 05:54
0.1ナノ秒の違いをそんなに気にしなきゃいけないランチャソフトって、どんなの?
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2005-10-20 09:05
うーん、コンパイラの最適化のみに頼るというわけではないですが、
速度より追い求めるべきなものがあるように思えますが...

引用:

・staticの扱い


高速化というよりは軽くはなります。逆は間違いなくありません。
なるべく静的で済むロジックは静的にしておきましょう。
コードの保守性にも寄与します。

引用:

・new で作るがclassではなくstructのもの


これが少々理解に時間がかかったのですが、値型によるオーバヘッドの軽減を見ればわかることなのかな?

引用:

usingで宣言すると速度に関係があるのか?


これと同じような話題でブロック変数にすべきか? というものがあります。
コンパイラの最適化を助けるため、using とブロック変数は使うべきです。
ただし、早くなる保証はありません。
using の場合は、安全性とかそういう部分に着目して欲しいと思います。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌

スキルアップ/キャリアアップ(JOB@IT)