2

プログレスバーを持つすべてのプログラムが、操作 (およびプログラムの作業の全処理) が完了するまでにかかる時間をほぼ正確に把握し、それをプログレスバーにマッピングできるようにする方法を常に考えていました。

C# では、プログレス バーを扱うときに常に困難に直面します。これに対する一般的な解決策はないという結論に達しましたね。

私はこれを求めていません:

「たとえば、ファイルの読み取りにかかる時間をどのように知ることができFile.ReadAllBytes(path)ますか? シンプルです。その前にストップウォッチを開始し、その後停止して時間を読み取ります。しかし、それはコンピューター、CPU、ディスク上だけです! - 1MB の読み取り値は、お使いのマシンや他のマシンとはほとんど異なります。」

内部に入る前に、物事が完了するのに必要な時間をどのように知ることができますか? File.ReadAllBytes()つまり、メソッドの実行中に進行状況バーがそれに応じてステップできるように、実行される前にどれくらいの時間がかかるかを知る必要があります。

これを行う愚かな方法の 1 つは、2 回行うことです。操作を開始して時間を計算し、再度実行するのですが、今度はプログレスバーをステップさせます(笑)

複雑さがこれと関係があるかどうかはわかりません。定義済みの関数を扱うときではなく、独自のメソッドや関数を記述するときに big-O を使用します。

編集: ほんの一例: ファイルを XOR し、XOR された形式で上書きするプログラムを作成しました。これには、ファイルのバイトをバイト配列に読み取る 1 が含まれます。それらを2-XORします。3-それらをファイルに再度書き込みます。進行状況バーを使用したい場合、これらの操作にかかる時間を知るにはどうすればよいでしょうか? それに応じて進行状況バーを増加させることができます。

これに対する私の解決策は、グローバル変数(prgBarなど)を使用し、XORを別のスレッドに割り当て、ファイルから読み取ったバイト配列からバイトをXORするたびにそのスレッドで「prgBar」をインクリメントすることでした。メインスレッドでは、タイマーを使用しましたが、ティックごとにタイマーを使用しました。prgressBar.Value = prgBar これには問題があり、正確ではありません。開始が遅れる可能性があります。

4

5 に答える 5

2

あなたの説明は停止問題です。簡単に言えば、任意のプロセスがいつ終了するかはわかりませんが、推測することはできます。

たとえば、転送する 1MB があるとします。一度に 1 バイトずつ転送し、1 バイトごとにプログレス バーを更新すると、スムーズに表示されます。過去に基づいた推定時間も表示できます。たとえば、1MB の 10% を移動するのに 1 秒かかった場合、9 秒で完了するはずです。

それが役立つことを願っています。

于 2012-12-11T22:03:54.773 に答える
2

簡単な答えは「そうではありません」です。プログレス バーが 20 秒の間に「残り 20 分」から「残り 5 分」にジャンプするのを見たことがありますか? それとも、「残り0:00」と言ってそこに座っている人ですか?


より良い答えは、「彼らは見積もります」です。これには 2 つの形式が考えられますが、詳細な調査は行っていません。ただし、どちらも過去のパフォーマンスを使用して将来の進捗を予測しています。

最初の形式は、ファイルのコピー/削除など、複雑さは似ているが任意の長さの一連の個別のタスクで機能します。低い基本見積もりまたは「計算中...」メッセージから始めて、各ファイルが終了したら、すべてのファイルをコピー/削除するのにかかる時間に基づいて、かかる時間を新たに見積もります。遠い。たとえば、2000 個のファイルを削除していて、最初の 5 個が で削除されて{400, 200, 900, 100, 400 ms}いる場合、2000 ミリ秒で平均 5 個のファイルを削除できることがわかります。つまり、2000 個のファイルを 800000 ミリ秒または 800 秒で削除でき、プログレス バーに「残り 13 分」(798 秒)と表示されます。正確ではないかもしれませんが、数ファイルごとに修正し続けると、かなりスムーズに進みます。

2 番目の形式は、タスクの長さとその複雑さがわかっている (そして大きく異なる) 場合ですが、インストーラーの場合のように、速度はまだ不明です。このシナリオでは、テストでインストーラーを何度も実行し、さまざまなコンポーネントの時間がどのように関連しているかを把握することで、見積もりを行うことができます。これは、個々のステップを比較して数式を導出するのと同じくらい複雑な場合もあれば、インストール時間のパーセンテージを各段階に割り当てるだけの場合もあります。次に、ユーザーがインストールを実行すると、コンポーネントの最初の 2% に相当する時間が X 秒かかったことがわかるので、残り 50*X 秒と見積もることができます。これが、インストーラーが頻繁にハングアップしたりジャンプしたりしているように見える理由です。予期せず通常よりも長い時間がかかる何かを待っているか、システムでステップを実行する必要がないことを発見しました。


結局のところ、それは単なる見積もりです。パーセンテージは難しいかもしれませんが (「私はステップ 1/5 にいるので、20% 完了したことを示してください」)、持続時間は決してそうではありません。この背後にある理論については、Jbecwar の回答を参照してください。

于 2012-12-11T22:29:27.230 に答える
1

Actually you should read the file in batches (eg. 20KB each time ) so you can increment the progress bar after each batch

于 2012-12-12T03:09:17.347 に答える
1

操作の完全性を自分で計算する必要があり、常に正確に計算できるとは限りません。ファイルを読み取るには、行数を取得し、読み取った行数を数えてから、 current/total を実行して進行状況を表示するなどのことができます。これは実際には、より複雑な操作の場合にはるかにうまく機能します。

データを処理する必要がある 1000 個のオブジェクトの配列があるとします。これを for ループで実行しているため、プログレス バーは単純に表示できますi/array.lengthReadAllBytesそのタスクの進行状況を取得する方法がないため、この例は適切ではありません。.NET メソッドはすべてのバイトを返すため、タスクの開始時と完了時のみを知ることができます。また、タスクが非常に高速であるため進行状況バーが不要になることは言うまでもありません。

于 2012-12-11T22:07:32.357 に答える
0

正解です。プログレスバーを「まだ処理中」のバーとして使用することを検討しない限り、プログレスバーに一度限りのサイズはありません。プログレスバーを0から100(最大)に何度も更新することができます。

進捗状況を把握し、ユーザーに報告できる場合があります。

あなたのFile.ReadAllBytes(path)例を見てみましょう:

ファイルのサイズを取得できるはずです。変数をインクリメントすることで、これまでに読み取ったバイト数を判別することもできます。簡単な計算を行うことで、bytesRead / bytesInFileを使用して、完了の割合を取得できます。500ミリ秒ごとにチェックするタイマーでこれをユーザーに報告してください。適切なフィードバックのあるプログレスバーが表示されます。

于 2012-12-11T22:02:09.877 に答える