web-dev-qa-db-ja.com

プログレスバー-なぜそれらが「有用」にならないのですか?

多くの人が以前にこれに気づいていて、これに悩まされるのは私だけではありませんが、プログレスバー(通常、単一のタスクではなく複数のタスクの実行の進行状況を表示するものを指します) -つまり、画像のアップロードではありません)、進行状況と所要時間を正確に表すことはめったにありません。

プログレスバーは2つのことを伝えることができます(またはできるはずです)。

  1. 特定の手順を実行するまでのコンピュータの距離。

  2. おおよその進行速度(満杯の速度-視覚的指標)

ただし、ほとんどのプログレスバーの性質はやや「ぎこちない」ものであり、以下の図のような理由がわかります。 

何らかの理由で、進行状況バーは完了するタスクの数が等しいセクションに分割されているように見えるので、私の例では、33%が他の66%の約6倍の時間がかかるタスクに割り当てられ、進捗状況の表現。

プログレスバー(私の例を続ける)は次のようになるべきだと思います: 

プログレスバーの大部分がこの例に従っていないように見えるのはなぜですか?さらに、なぜ特定のタスクを10分間停止するのではなく、進行状況バーが一定のペースでいっぱいにならないのか、インストーラーがクラッシュしたのか、それとも大量の情報を処理しているのかをユーザーに知らせないのです。後者の場合、なぜそのプロセスがさらに分解されて進行状況バーに表示されないのですか?

31
Anonymous

あなたはそれが悪いと思う?場合によっては、プログレスバーはそもそも何にも関連付けられていません。スクロールアニメーションを表示するだけで、ユーザーを落ち着かせることができます。

どうしてこれなの?まあ、私はインストーラツールをよく知りませんが、私が見たことから、ほとんどのオフペグの進行状況インジケータは、インストールスクリプト内のコマンドの数に純粋に依存しており、開発者に余分な「時間」を割り当てさせませんまたは特に時間のかかるものへの「重み」。

さらに、インストール時間の見積もりは簡単ではありません。従来、インストーラーはファイルのコピーに使用されていたため、進行状況バーをシフトされたバイトの割合を反映するように設定することができましたが、最近のインストーラーはより複雑です。インストーラーは、クライアントマシンに特定のライブラリが存在するかどうかを確認するか、インターネットに接続して更新を確認する必要があります。このようなことは、本当に役立つプログレスバーを構築することを困難にします。問題に取り組む意志がなければ、だれもこの問題に取り組むことはできません。

ただし、不適切に実装された進行状況インジケーターの言い訳にはなりません。これらの「ノンリニア」プログレスバーの最大の問題の1つは、インストーラーがクラッシュしたとき、または単に大きなタスクを非常にゆっくりと処理しているときに、それらがわかりにくいことです。これにより、「クラッシュした」と思われるインストーラーを途中で閉じるようにユーザーに求めることができます。これにより、オペレーティングシステムが損傷したり、将来のインストールが複雑になったりするおそれがあります。今日のアプリケーションでは、それは受け入れられません。

32

progressバーを使用してstepsは完全に間違っています、IMO。

私はそのようなタスクのためにプログレスバーを厳密に使用します、

  1. タスクの時間/サイズを1つの単位(秒/メガバイトなど)で予測できます。
  2. タスクをプログレッシブユニットに分割できます。すべてのユニットのウェイトは同じです。
  3. プログレッシブユニットの完成度を計算できます。

したがって、ダウンロードしてからインストールすると、neverが1つの進行状況バーに表示されます。ダウンロード/インストールユニットの重みは同じです。


シナリオ例:タスクには、ダウンロード、インストール、構成の3つのステップがあります。ダウンロードが完了し、インストールが30%完了し、構成が開始されていません。

この種の情報を表示する方法はいくつかあります。

タスクリストと単一の進行状況バー

+-----------------------------------------------------------------------------+
|  x Download       | Progress:                                               |
| -> Install        | [============----------------------------]         30%  |
|    Configure      |                                                         |
+-----------------------------------------------------------------------------+

複数のプログレスバー

+-----------------------------------------------------------------------------+
|                   | Progress:                                               |
|    Download       | [========================================]        Done  |
| -> Install        | [============----------------------------]         30%  |
|    Configure      | [----------------------------------------]     Pending  |
+-----------------------------------------------------------------------------+

もちろん、これら2つのUI概念を設計する方法は無数にあります。


さらに、パーセントの横に(または代わりに)単位を表示できます。例えば。:

  • ファイルをダウンロードする:

    [============----------------------------]  30% (26.7 of 89.0 MB)
    
  • アーカイブの抽出:

    [================------------------------]  40% (2617 of 6543 files)
    

注意点

  • 私は常に進行の単位を選択するようにしていますので、ユーザーに嘘をつく必要はありません。たとえば、timeでダウンロードの進行状況を測定していません(私はできないので!)。それは常にバイト/キロバイト/メガバイトでなければなりません。
  • 進行状況を確実に計算できない場合、進行状況バーは表示されません。たとえば、「一時ファイルの削除」ステップの進行状況を計算するための適切なユニットがありません。これらの状況では、不確定な進行状況バーを使用します。

    [---------------====--------------------]  Deleting temporary files...
    
14
sampathsris

プログレスバーがそれほど正確ではない理由は2つ考えられます。

  1. 開発者は怠惰です。または
  2. 一部のタスクでは、それに比例してどれだけの時間がかかるかを推測したり決定したりすることは本当に難しいです。たとえば、データベースにクエリを実行し、レコードの数を返し、それらを使ってWebサービスにアクセスするタスクの進行状況バーを考えてみましょう。アプリのコーディング時に、返されるレコードの数を知る方法はありません。 Webサービスへのアクセスにかかる時間は、ユーザーの接続速度によって異なります。

マイクロソフトの議事録を聞いたことがありますか? :)

7
Jaco Briers

1)ソフトウェアの「ロード」および/またはインストール中に、各プロセスにかかる時間を決定するのに多くの困難があります。だからこそ、かなりぎくしゃくしています。

2)これが当てはまらない場合でも、私たちが時間を認識する方法に干渉するため、低速から高速に移行することは依然として有益です。スロースタートとそれに続く速度の増加により、ユーザーの煩わしさが減少します。

そして、私が自分の2セントを投入する場合は、最後の10%で年齢を待つことほど厄介なことはありません。したがって、最初は多くのプログレスバーが遅く、ぎくしゃくしていて、後半は途方もなく速くまたは瞬時に発生します。

5
Dirk v B

進行状況バーが一定の速度で進行しない理由の1つは、「実際の」進行状況を示すためのものです。したがって、タスクが完了するまで、進行状況は視覚化されるべきではありません...しかし、それはユーザーにとっては不満かもしれません。

私が気付いたことの1つは、プログレスバーは目標指向ではなくタスク指向であることです。 1つのファイルがコピーされ、次に別のファイルが表示されます。これは、目標を完了するのにかかる時間を実際に示すものではないため、役に立ちません。

一方、目標指向の進行状況バー(提案した方法)は、一部のサブタスクがオプションになる可能性があるため、達成が非常に難しい場合があります。

そうは言っても、私はあなたの考えが好きですが、現実には、世界は無能な人(うん、そうですか?)プログラマー/アナリスト/コンサルタント(または怠惰、あるいはその両方)でいっぱいです。

編集:私はジミーと一緒です。それは些細なことではありませんが、翼を振るだけでは受け入れられません。

4
GUI Junkie

他にも述べられているように、特定のハードウェアでタスクが実行される時間を知ることは不可能です。インストーラーがAからBにファイルを移動するだけではない場合、たとえば、インストール中に別のコンピューターからより多くのファイルをダウンロードする必要がある場合、または別のプログラムを閉じる必要がある場合(そしてユーザーが現在使用中のファイルまたはサービスを置き換えるために、手動で閉じてください。

さらに厄介なのは、100%に達した後、0%から再び始まるプログレスバーです。 Win95領域の一部の古いインストーラーは、時々コピーされた各ファイルの進行状況を示していました。そのため、インストーラーが10個または500個のファイルをコピーしようとしているかどうかはわかりません...

4
iHaveacomputer

プログレスバーのポイントを逃したと思います。これらは、タスクの進行状況を表すことを目的としたものではなく、タスクがスタックしていないことを示すことを目的としています。 Windows 7のプログレスバーはときどき点滅するので、動いていない場合でもスタックしていないことを示します。一部のソフトウェアは、「ビットを採用しています...」、「ビットをバイトにパッキングしています...」、「メモリリーク保護保険を取得しています...」など、まったく関係のないメッセージで進捗状況を表示しません。

一部のプログレスバーは対数スケールを使用し、10秒ごとに未完成部分の半分を進めます。そのため、常に進行しますが、バーは(タスクが完了するまで)満たされません。

もちろん、ここではタスクがスタックする可能性があり、タスクがスタックしていないことをプログレスバーがユーザーに保証し続けるという問題があります。

必要な時間を正確に推定し、それに応じて進行状況バーを移動することは、他の回答に見られるように非常に困難であり、ほとんど無意味です。あなたができる最善のことは、進行状況があるときに移動し、タスクがスタックするときにスタックする進行状況バーを作成することです。場合によっては、プログレスバーが動かなくなってから続行され、プログレスバーに意味があることがユーザーに保証されます。どれだけ速く動くかは問題ではありません。それがごまかしのように見える場合は、進行状況バーをyoutubeのビデオ読み込みアニメーションのような周期的なアニメーションに置き換えることができます。

4
nwp

ほとんどの場合、フェーズ数のチェックリストを使用し、操作の数がわかっている場合は、進行状況バーを使用することをお勧めします。コピーするファイルの数やその合計の長さがわかっている場合のコピーなど。それ以外の場合は、操作の数が不明な場合は不確定な進行状況バーを使用します。

oPの例から、ファイルのコピーと削除のフェーズは長さがわかっているため、進行状況バーを使用する必要がありますが、インストールの長さが不明であるため、不確定な進行状況バーの方が適しています。

1
Dan D.

これはコード化された例に値すると思いました:

10個の名前のリストを処理しているとしましょう。

_Harriet
Charlie
Ruth
Peter
Bill
John
Alistar
Ken
William
Robert
_

これらの名前は、プログラミングでは配列と考えることができます。たとえばJavaScriptでは:

_names = ["Harriet","Charlie,"Ruth","Peter","Bill","John","Alistar","Ken","William","Robert"]
_

次に、これらの名前を処理します。

_names.forEach(function(name){
    if(isMale(name)){
        sleep(10000) //imitate a long algorithm
    } else {
        sleep(100)   //imitate a short algorithm
    }
})
_

これで問題が発生することがわかります...名前が男性のものである場合、アルゴリズムの完了には10秒(10,000ミリ秒)かかります。ただし、名前が女性に属する場合、アルゴリズムは完了するまでに0.1秒(100ミリ秒)かかります。これは簡単に回避できるものではありません。それはあなたが与えられた仕様によるものです。

今。あなたが考えるかもしれないことは、次のことをすることです:

_var males,females;
names.forEach(function(name){
    if(isMale(name)){
        males++;
    } else {
        females++;
    }
})
var maleTime = males*10000;
var femaleTime = females*100;
var totalTime = maleTime + femaleTime
var males,females; //reset to 0
names.forEach(function(name){
    if(isMale(name)){
        males++;
        sleep(10000) //simulate a long algorithm
    } else {
        females++;
        sleep(100)   //simulate a short algorithm
    }
    setProgress(males,females,totalTime)
})
_

それはすばらしいことですが、今では、男性の名前と女性の名前のアルゴリズムは、すべての人のシステムで同じ時間かかると想定しています。この場合、sleep()を使用してシミュレーションしているため、時間が一定であることをほぼ保証できます。ただし、実際のアルゴリズムでは、マシンごとに変化します。

したがって、現実の世界では、次のように何かを行う必要があります。

_var males,females;
names.forEach(function(name){
    if(isMale(name)){
        males++;
    } else {
        females++;
    }
})
var realMaleTime = doAlgorithmFor("genericMale")
var realFemaleTime = doAlgorithmFor("genericFemale")
var maleTime = males* realMaleTime;
var femaleTime = females*realFemaleTime;
var totalTime = maleTime + femaleTime
var males,females; //reset to 0
names.forEach(function(name){
    if(isMale(name)){
        males++;
        sleep(10000) //simulate a long algorithm
    } else {
        females++;
        sleep(100)   //simulate a short algorithm
    }
    setProgress(males,females,totalTime)
})
_

さて、それで終わりです!簡単でした!ええと...まったく違う...同じことがコード内のすべてのフロー制御に当てはまります。この長いアルゴリズムは、この動作を持つフロー制御も含まれる可能性が高いため、さらに詳しく調べる必要があります。各フロー制御は同じ方法で検査する必要があり、進行状況バーがすべてをラップします。

そしてもちろん、フロー制御のすべての部分のすべての進行時間の計算が終了し、アルゴリズムがデータセットにかかる時間を正確に計算すると、最初よりも多くの作業が完了しています...したがって、アルゴリズムにかかる時間を確認するためのアルゴリズムには、おそらく独自の進行状況バーが必要です。

したがって、一般に、他の人のマシンでのアプリケーションの動作を予測することは常に不可能であるため、実際にはよりインテリジェントです。

_var iName=0;
names.forEach(function(name){
    if(isMale(name)){
        sleep(10000) //imitate a long algorithm
    } else {
        sleep(100)   //imitate a short algorithm
    }
    setProgress(iName++,names.length)
})
_
0
Sancarn