C#, C♯, C#相談室 Part94

■ このスレッドは過去ログ倉庫に格納されています
1デフォルトの名無しさん (ワッチョイ 935f-5Uxj)
垢版 |
2019/03/20(水) 18:57:36.47ID:ZZcTomnN0
!extend:checked:vvvvv:1000:512
■Visual Studio 2017 Community(無償の統合開発環境)等はこちら
http://www.visualstudio.com/downloads/

■コードを貼る場合はこちら
http://ideone.com/

■前スレ
C#, C♯, C#相談室 Part93
http://mevius.5ch.net/test/read.cgi/tech/1492818720/

■次スレは>>970が建てる事。
建てられない場合は他を指定する事。
VIPQ2_EXTDAT: checked:vvvvv:1000:512:----: EXT was configured
2021/07/03(土) 05:01:54.92ID:DAcib8Yu0
>>572
では早速言い出しっぺのあなた様から肝臓を差し出して下さい
2021/07/03(土) 06:04:33.61ID:+HNBKtJi0
では血をとらずに肝臓だけ取り出してください
2021/07/03(土) 09:59:13.80ID:gTgAsOHbM
何そのハムレット
2021/07/03(土) 10:22:53.43ID:ZeViGhZj0
アンキモ以下の脂肪肝なら処分料が欲しいな
2021/07/03(土) 11:22:03.96ID:fanuEOjba
ヴェニスの商人では?
578デフォルトの名無しさん (ワッチョイ 6f54-SLQ7)
垢版 |
2021/07/05(月) 15:24:59.38ID:ZSz/R5WI0
DBから取得した重複なしの文字列List (要素数約4000) をComboBoxのDataSourceにセットする処理が、
約900ms〜1100msかかり、その間Formが固まるのですが、どうすれば固まるのを回避できるでしょうか。

A5M2でSELECTクエリの所要時間を見ると、だいたい700ms〜900ms台で、ここは改善のしようがなさそうです。
2021/07/05(月) 15:45:29.72ID:5mYpWHh80
ComboBoxで4000の中から選ぶのは大変そうだな
DataSourceに設定する前後にComboBox::BeginUpdate/EndUpdateを呼べば多少は改善すると思う
それ以上はComboBoxじゃ無理じゃないかな 仮想モードもないし
2021/07/05(月) 16:04:21.63ID:yitPGA0i0
やばそう
2021/07/05(月) 16:35:24.72ID:lQZs6uo50
>>578
DBからデータ取得する処理は非同期に
2021/07/05(月) 16:53:08.67ID:S2aqSQgd0
>>578
DBから取得する部分を別スレッドで動作するasyncメソッドにするです
UIの更新は別スレッドなのでInvokeで
2021/07/05(月) 17:11:11.76ID:ynDVyPDO0
awaitしとけばUIスレッドに戻ってくるからInvoke要らんだろ
2021/07/05(月) 17:14:42.74ID:ZSz/R5WI0
みなさんありがとうございます。
BeginUpdateとEndUpdateで20〜40msほど早くなりました。

現状、DBからの取得部分は別スレッドにしています。
ただし、フォーム表示時に、
@ComboBox の DataSource に List をセット。
A別の個所で設定した値で、ComboBox.SelectedItemを決定。
BComboBox.SelectedItem に応じて、それに対応するデータを DataGridView に表示。
という処理をしているので、結局ComboBoxへのDataSourceセット待ちになります。

むしろUIと同じスレッドでデータ取得すればスレッド切り替え処理がなくなって微妙に高速化出来るんじゃ?と思ってます。
2021/07/05(月) 17:33:32.24ID:ZSz/R5WI0
データ取得をUIスレッドで行ってみましたが、別スレッドでしたケースと比較して、実行するたびに優劣変わる程度でした。
これ以上の改善は無理そうなのでいったん諦めます。
2021/07/05(月) 17:41:30.27ID:lQZs6uo50
Formが固まるのを回避したいってのは高速化したいということだったのか・・・
ま、がんばって
2021/07/05(月) 17:41:33.62ID:ykFrWqkT0
>>578
転送時に圧縮かけたら高速化するんじゃね

構成わからんからあてずっぽうでいうけど
DBサーバと近いWEB鯖のPHPでデータ一覧取得してJSONとかで転送(要するにPHPでAPI作成)
サーバの設定等でHTTP圧縮をON
圧縮かかってるから転送そのものが高速化される

どうやって圧縮かけるかは他にも色々やり方あるだろうけどね
LAN内に全てそろってる(例えば同一PC内)としてもかなり速くなるはずだよ

クエリで700msってのが気になるけど時間かかりすぎじゃないかな
Explainみた?

プロファイラはどう?昔はEQATEC Profiler使ってたけど今は何がいいんだろうね
どこにどれぐらいの時間がかかってるかわからないと理論値と比較できない

初見の感想は4000件程度で700msもかかってるのが気になる
応答だけ?それとも結果の羅列まで込みの時間かな
クラサバでそんなにかかる処理ってあまりないと思う
2021/07/05(月) 17:46:44.69ID:ykFrWqkT0
そもそも一瞬で取得すれば固まらないからね
あとはUIに先回りして裏で取得するとか、DB側でキャッシュするとか、小出しにしていくとか・・・

まぁ、一番簡単なのは画面にプログレスバー出してめっちゃ高速に処理してる風を装う事とかだけど

ただ、何も知らずに直観でいうと100msは切るはず
2021/07/05(月) 17:58:05.85ID:7JzKdw7cD
実処理時間と言うより、
取得中に割り込み入れないと固まったように見えるってだけの話では
2021/07/05(月) 18:09:58.95ID:ynDVyPDO0
時間が掛かっているのはデータ取得の部分じゃなくて
取得したデータをコンボボックスに渡す処理(>>584の@)だから
>>579が全てだな
2021/07/05(月) 19:11:56.65ID:IA8ZeXCsa
たぶん「犯人」はComboBoxだろうが一応問題の切り分けが必要だと思って
public Form1()
{
  InitializeComponent();
  var asm = Assembly.GetAssembly(typeof(Form));
  var bl = new BindingList<Type>();
  foreach (var item in asm.GetTypes()) bl.Add(item);

  var sw = Stopwatch.StartNew();
  comboBox1.DisplayMember = "Name";
  comboBox1.DataSource = bl;
  Console.WriteLine($"Time = {sw.ElapsedMilliseconds} ms, Number of Items = {bl.Count}");
}
こんなコードを書いてみた。10年前のポンコツPCで実行してるが約2400個のアイテムをぶち込むのに
デバッグモードでも10ms程度の時間しか掛からない。

つまり「犯人」はComboBoxじゃないんじゃないの?知らんけど。
2021/07/05(月) 19:44:16.85ID:ynDVyPDO0
>>591
フォームのコンストラクタで測ってるけど、フォームがロードされた後で測るとかなり変わるよ
うちの環境ではデバッグビルドで、コンストラクタ:3msec、Loadイベント時:226msec
2021/07/06(火) 01:07:39.66ID:AJxevGXU0
DB の実行計画を見れば?
インデックスを使わずに、全件探索でもしてるのでは?

2分探索なら、2 ^ 10 = 1,024
2 ^ 12 = 4,096

つまり、12回探索するだけ

ミックの本でも読んだ方がよい
2021/07/06(火) 07:28:36.60ID:kC5iABNna
>>593
その前にソートな
2021/07/06(火) 07:38:26.90ID:4w9diVqq0
何言ってんだこいつ
2021/07/06(火) 07:47:40.70ID:Jcre+LWcM
インデックス張ったら挿入や更新の度に毎回ソートしてるとでも思ってるんだろ
2021/07/06(火) 08:22:21.59ID:PbL+Rk1v0
全件探索なら1回探索するだけ♪
2021/07/06(火) 08:54:22.76ID:4hP0mNbe0
約900ms〜1100msの処理のうち
クエリが700ms〜900ms台で、改善のしようがないっていってるんだから
それがホントなら速度的なものはどうしようもないと思うんだが

画面が固まる対策ならクエリを非同期に(正確にはUIスレッド以外で、か)しろで終わりだろ
2021/07/06(火) 09:08:47.43ID:juTGPN6qM
ルビおじに絡むおじさんはルビおじよりさらに無能だからな
2021/07/06(火) 11:25:26.74ID:J1QHRuI00
やったことないけど、コンボボックスも仮想化できるらしいから試してみたら?
データ取得を非同期に出来てるなら画面が固まることは無くなりそう
https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/advanced/optimizing-performance-controls?view=netframeworkdesktop-4.8#controls-that-implement-performance-features
2021/07/06(火) 11:36:28.26ID:azFxX9aU0
>>600
それWPF
>>578はWinFormsみたいだけど
2021/07/06(火) 18:11:30.42ID:RaE3JhC/0
WinFormsのComboBoxに仮想モード追加する例ってありそうで無いな
2021/07/06(火) 21:55:13.16ID:Rt0qzyHm0
じゃ俺がWinFormsのComboBoxを仮想化する知恵を貸そうか?
2021/07/06(火) 22:04:24.92ID:4w9diVqq0
まああてにするな
2021/07/06(火) 22:18:48.94ID:HsJYefQaa
どうぞどうぞって言おうと準備してたのにw
2021/07/07(水) 02:05:48.56ID:jIHjttY10
じゃあ代わりに言うか
「どうぞどうぞ」
2021/07/07(水) 03:00:22.72ID:sX4an4wR0
みなさん本当にありがとうございます。

原因は、約4000の要素をDBから取り出す所要時間でした。
約60万レコード内の、文字列カラムのデータを、重複しないように、GROUP BYする処理が時間食ってました。

なので、該当の文字列カラムだけを重複なしで格納するキー一覧テーブルを作り、
データINSERT時に、キー一覧テーブルの既存レコードと一致しない文字列だけをキー一覧テーブルに追加するトリガー処理を作りました。

そして、ComboBox の DataSourceにはそのキー管理テーブルのデータをセットするようにして、表示所要時間を5〜6割短縮出来ました。
2021/07/07(水) 06:50:16.04ID:oDfnQi3+M
高々60万レコードの group by に700msって遅くね?
DBMS 何使ってるのかわからんけどインデックス張るだけで良いような気もするが…
2021/07/07(水) 07:38:37.09ID:F/xqoSBh0
マテリアライズドビュー作るとか
2021/07/07(水) 10:41:15.77ID:qNxZ5hgE0
GROUP BY自体が遅いもんよ
SQLが悪いとインデックス使っても無視されてFULL検索になってしまう
2021/07/07(水) 12:33:18.92ID:GxuaumQya
それより結局ComboBoxは何の関係もなかったってことだよね?

つまりボトルネックがどこにあるのか計測して確認もせず思い込みで
ComboBoxが悪いとミスリードな質問をした。

ここは反省して欲しい。
2021/07/07(水) 12:57:56.68ID:urFk1IqDa
>>611
やれやれ
2021/07/07(水) 13:00:11.32ID:FuIb4wxP0
最初の質問で問題の処理に約900ms〜1100msかかっていてそのうちクエリの所要時間が700ms〜900ms台と書いていて、その上でクエリ以外の部分(約200ms)を改善したいという話だったから測ってないわけではないかと
クエリ部分は改善不可能と思い込んでたのはあるが
2021/07/07(水) 13:00:41.99ID:ylMxxyrU0
>>611は毎度お馴染みで皆さんご存知の、
ComboBoxに責のあるマイクロソフトの犬
2021/07/07(水) 15:16:07.20ID:Z3N+pbe10
最初に戻ると結局画面は固まってなかったってことなんだろうな
これが一番のミスリード
2021/07/07(水) 15:26:49.85ID:jKQg8TjQ0
FormのLoadで何も表示されないまま1秒以上かかるとかなり固まった感は強い
だからスプラッシュやプログレスバーというのは非常に大事
これがあるだけでクレーム率はかなり下がる

速度最適化というのは実際のレスポンスやスループットだけではなくて
体感速度も最適化するべきなんだ
2021/07/07(水) 15:38:40.22ID:O4oUzSnJ0
いや、クエリの間は固まってたんじゃね
そういう意味ではコンボボックスは無関係だな
2021/07/07(水) 19:17:38.62ID:Z3N+pbe10
別スレッドで取得してるって言ってんのに?
2021/07/07(水) 20:02:39.26ID:vUBZA2na0
別スレッドの処理終了を同期で待ってたら固まるよね
2021/07/07(水) 20:04:38.68ID:iooPCaard
別スレッドでの取得結果を待たずにコンボボックスが表示できるとは知らんかった
2021/07/07(水) 20:05:37.60ID:UGIg3KO/0
空のはできるんじゃないの?
2021/07/07(水) 20:07:38.45ID:iooPCaard
>>621
それが期待する動作だったとは読み取れなかったわ…
2021/07/07(水) 20:37:31.96ID:vUBZA2na0
なるほど
同期で待つのと非同期で待つ違いがわかってなかったのか
2021/07/07(水) 20:54:47.64ID:GxuaumQya
>>613
なるほどね。読み返してみると確かにそういう風に読めないこともない。
でもその解釈だと辻褄が合わないように聞える部分もいろいろあるね。
まあ揚げ足取りは本意じゃないのでこれで
2021/07/07(水) 21:14:19.97ID:WowgMcxm0
>>610
group by の動作原理考えればそうでしょう
ソートと集計の複合技でっせ

EFを初心者に進めたくないのがその辺りかな
実行計画取れやと言いたくなって来る
2021/07/07(水) 21:32:17.55ID:PTZA0JCFM
>>622
期待する動作は
> その間Formが固まるのですが、どうすれば固まるのを回避できるでしょうか。
だよ?
2021/07/07(水) 23:15:16.70ID:O4oUzSnJ0
その間ってのがどこからどこまでか
固まるとはどういうことか
が、普通に考えるのとずれてるんだがな
2021/07/08(木) 05:59:22.31ID:bp32MkoMa
>>623
初心者なので詳しく教えてください。
2021/07/08(木) 06:08:48.29ID:4npUp7i4M
お前さんの普通なんて知らんがな
2021/07/08(木) 07:08:26.32ID:ynxscpbq0
今回みたいなケースは再現しようがないから想像するしかないんだよな
齟齬が出るのはしょうがない
631デフォルトの名無しさん (ワッチョイ 355f-xNKK)
垢版 |
2021/07/10(土) 10:35:48.26ID:o1Fr1a0g0
メインウィンドウが開かれるのに時間がかかる場合って自動的にマウスカーソルに砂時計付くよね
これってWindows 10だけの機能なのかな?
スプラッシュはそういうことに気付かない人にはわかりやすいからいいと思うけど
2021/07/11(日) 15:20:44.65ID:ODsLgHFcM
C#について詳しくなりたい。
.net独学だからテクニックが全く身についてこない。
働きながら学べる人たちが羨ましい。
2021/07/11(日) 16:47:39.95ID:UTF+PuFAM
>>632
働いてはどうでしょうか
2021/07/11(日) 16:53:56.36ID:JpOAcHlL0
>>632
Effective C#とMore Effective C#買って読めば
2021/07/12(月) 09:28:12.82ID:ReFnqSuP0
>>632
オープンソースのソフトウェアをただそのまま使うのではなく
自分で使いやすいよう改造して使ってみたらどうかな
2021/07/12(月) 14:04:49.78ID:DOYT8O/O0
ひとが使いためのライブラリ作らない限りテクニックなんかロクに身に付かんでしょ。
テクニックが要らないように作られれてるのが人気があるライブラリなんだから。
2021/07/12(月) 17:05:33.06ID:ihSDWtOf0
async・awaitを使った非同期処理の並列処理数をSemaphoreSlim使って制御しています。

https://qiita.com/tadokoro/items/28b3623a5ec58517d431
を見ると、SemaphoreSlimのパフォーマンスはそこまで良くないらしいんですが、async・awaitを使いつつパフォーマンスを上げる方法はないでしょうか?
並列処理数の上限は4が理想です。※多ければ多いほどいいのはいいです。

SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1,4)
await semaphoreSlim.WaitAsync();
try {
await 自分の非同期メソッド
}
finally {
semaphoreSlim.Release();
}
2021/07/12(月) 18:01:24.85ID:AiE5hxvs0
必要な場所にだけlockを掛ける
lock不要なロジックにする
2021/07/12(月) 18:04:26.22ID:hnMq5MVY0
>>637
await,asyncはlock使えないから基本>>638の通り排他不要にするか、そのコードで頑張るしかないんじゃね
2021/07/12(月) 18:33:51.33ID:4WArcuIG0
>>637
そのベンチマークは同期のオーバーヘッドを気にするくらい
ゴリゴリ共有リソースにアクセスする場合のための比較だから
4並列でawaitするような処理をする場合とは全然違うものじゃない?
2021/07/12(月) 19:18:50.72ID:xUxV3tpC0
async,awaitってlock使えないのか。。
2021/07/12(月) 19:21:57.66ID:ihSDWtOf0
>>638-640
ありがとうございます。
必要な場所にだけ lock 使うようにします。
lock 不要に出来るかも検討してみます。
2021/07/12(月) 20:54:40.73ID:LswkHmLx0
これだけだとロックのパフォーマンス差なのかawaitのオーバーヘッドなのか分からん気がする
2021/07/16(金) 12:04:19.61ID:JqVxPGJSd
#region を使うのは駄目ですか?
開くの面倒だ!ってセンパイに怒られました・・・
2021/07/16(金) 12:24:45.09ID:QqSxNnhma
うちじゃ使わなかったらレビューで指導が入るけど
2021/07/16(金) 12:30:58.12ID:81zoecY+0
コーディング規約に従え
個人的には使わないし他人が使ってても気にしない
メソッド1個ずつにregionあったらちょっとうざいけど、ショートカット一発で全部開けるしどうでもいいかな
2021/07/16(金) 12:53:50.69ID:QqSxNnhma
>>646の言う通り
うちには規約にregionについての記載があるのでその通りにしなかったらレビューの指導対象
こんなことをここに書き込むと言うことは
>>644は規約を読んでないか規約そのものがないかのどちらかだと思うけど
2021/07/17(土) 06:06:49.16ID:Mspzx0w60
規約ちょうだい
2021/07/17(土) 11:35:23.95ID:tiRnOuXY0
regionは規約がないなら使わないのが無難
特に〜のプロパティ、〜のメソッドみたいな囲いかたは最悪で、今後regionを意識してメンテしなきゃいけないのが面倒
折りたたまないと把握出来ないほどぐちゃぐちゃになってますって言ってるようなものだしね
2021/07/17(土) 14:53:32.71ID:Wlqcfoar0
#region (規約)
把握できないほどグチャグチャになるくらいなら囲んだ方がマシ
#endregion
2021/07/17(土) 19:23:55.27ID:1SEym9JY0
画面のクラスとかだとregion的な機能つかいたくなることはあると思うけどなあ。
画面って結局、人間にとって都合のいいように複数のデータを出すものなので、そのデータ毎にregion作ったりするのは変じゃないと思うけど。 Formに依存するコードを、 Form外の別クラスに書いたりしたくないじゃん。
2021/07/18(日) 01:36:46.77ID:jHDjUzT3d
コメントを書かない論者と同じ臭いがする

誰が読んでも自然言語と同じレベルで即座に理解可能かつ
解釈の余地の入らない完璧なコードを書けていて
しかもチームの全員がそのレベルに達しているという
地球上に存在しないチームで働いているかのような思い込みをしている
2021/07/18(日) 02:29:32.38ID:fZXK3W//0
自分しか読まない使い捨てのテストコードならコメントも書かないし、ましてや#regionなんて使わない
2021/07/18(日) 02:41:59.86ID:gMJXIBls0
#regionはあまり使わないが
IDisposableパターンの実装とか定型文的なのはでregionで畳んでおくな
2021/07/18(日) 07:23:51.05ID:Ncq1Qbn/0
俺もそんな感じだな
インターフェースを継承するクラスは定形文が多くなるから囲んで畳んじゃう
2021/07/18(日) 09:20:30.72ID:SEUoEBF50
IDisposeパターンなどはpartialでクラスごと隔離するのがお薦め
2021/07/18(日) 10:15:41.72ID:f26THqN50
子供は肉が好き!
2021/07/18(日) 10:18:34.20ID:duOzNEUP0
partialはお勧めかなぁ?
一見、Disposeが必要なメンバーを持っているのにIDisposableパターンを実装し忘れたクラスに見えてしまいそう。
2021/07/18(日) 11:31:45.33ID:SQx5QkWC0
自動生成してくれるならpartialでもいいけど自分で書くなら俺はやはりひとつのクラスにするな
2021/07/18(日) 19:03:11.29ID:x1tAdumV0
VSでクラスから別に定義されたpartialクラスに飛ぶ方法がよく分からないので、partialは使わない。
2021/07/18(日) 19:38:24.99ID:SQx5QkWC0
まあクラスに飛ぶとか言ってる時点で使わない方が無難だろうね…
2021/07/18(日) 21:11:55.98ID:wT9cmlucd
F12とかCtrl+F12とかできなかったっけ
知らんけど
2021/07/18(日) 22:09:14.51ID:zdDSWDaE0
>>661
言い方が雑なだけでおかしなこと言ってるようには見えないけどなあ
2021/07/18(日) 22:10:16.34ID:ZnA++D2G0
partial は元々自動生成コード用の機能であってクラスを分割する機能ではない
明らかインターフェイスの実装を#region化する方が可読性が高い
2021/07/19(月) 02:47:17.54ID:GZMIZdMt0
>>663
相手を否定せずにはいられない可哀想な人達が一定数いるから、そっとしておいてやりなよ。
2021/07/19(月) 10:43:55.05ID:uTNe/jhZ0
partialでクラスを分割してもファイルは1つのままでも問題ない
目障りなコードを#regionより明確に隔離できるから良いんだけどね

まあ1クラス1ファイルの規約が有るなら無理だけど
667デフォルトの名無しさん (ワッチョイ 9d5f-NvNM)
垢版 |
2021/07/19(月) 20:59:17.78ID:yGPED6YR0
partial→見るな触るな
region→見てもいい触ってもいい

という使い分けになりそう
2021/07/19(月) 21:29:24.97ID:K3gEK6ANa
そんな教条主義的に考えなくてもいいでしょw

トポロジー的(?)には部分クラスは本の1巻2巻、
#regionディレクティブは章に近い感じがするので必然的に部分クラスの方が
出番は少なくはなるわね。

何のために使うべきか、何のために存在するかってそれじゃ哲学だw
エンジニアリングの発想は「何に使えるか」でしょう
2021/07/19(月) 21:50:47.13ID:6cdKHupi0
#region 定数
#endregion

#region 変数
#endregion

#region プロパティ
#endregion

みたいに整理?
2021/07/19(月) 22:17:06.00ID:YnDE/De/0
クラスの一部をT4で生成させたときに手で書いた分とファイル分けてpartialにするのとかやったことはある
regionはIDisposableとかインタフェース実装した時に囲っておくのはよくやるし、
>>669 みたいな使い方するときもある
2021/07/20(火) 07:33:24.30ID:DOoV4fKqM
定数が増えるなら外部ファイル定義にしろ
変数やプロパティが増えるならクラスを分けろ
と思ってるから滅多に無いが、何らかの理由でやむを得ず肥大化した時は>>669のやり方してるな
2021/07/20(火) 12:11:28.91ID:npAM0kVy0
フォルダ整理と似た話だよね
regionってつまるところデスクトップにアイコン敷き詰めてるやつが画面上で1列空けてわかりやすいでしょって言ってる感じ
フォルダ作るなりツールなりで管理した方がと思うけどそれが本人にはわかりやすいんだろうな
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況