「残り1秒」を眺めながら、もう30秒たった。ようやく終わると思ったら、今度は「残り2分」に戻った。
ファイルのコピー、アプリのインストール、動画の書き出し。進捗バーは便利ですが、ときどき時計とは違う世界で動いているように見えます。
実際、進捗バーは時計ではありません。進捗率は「どれだけ終えたか」、残り時間は「これからどれだけかかりそうか」、完了は「必要な処理が成功したか」です。 この三つを分けると、「99%なのに終わらない」の見え方が変わります。
この記事ではWindowsのAPIやUIの資料を手がかりに、一般的な仕組みを説明します。特定バージョンのエクスプローラーの内部アルゴリズムを解析した記事ではありません。数値例と比較デモは説明用の仮想処理であり、PCや回線の実測値ではありません。
1. まず「何の100%か」を確かめる
100件の書類を確認するとしましょう。99件が短いメモで、最後の1件だけが分厚い契約書なら、「99件終わった」は正しくても「時間も99%終わった」とは限りません。
進捗表示でも、分母を何にするかで意味が変わります。
| 表示の基準 | 50%が意味すること | その数字だけでは分からないこと |
|---|---|---|
| ファイル件数 | 対象の半数を処理した | 残りのファイルの大きさや処理時間 |
| データ量 | 対象バイト数の半分を処理した | 残りの速度や、転送以外の工程 |
| 工程の重み | 決めた配分の半分まで進んだ | 配分が今回の所要時間に合うか |
たとえばWindowsのCopyFileExで使う進捗コールバックは、ファイル全体のバイト数や転送済みバイト数を渡します。これは作業量の情報であり、未来の秒数を直接渡すものではありません。1
flowchart TB
accTitle: 進捗率と残り時間と完了の違い
accDescr: 処理済み量から求める割合、速度を仮定して求める残り時間、成功結果による完了を別の情報として示します。
A["処理済み量と総量"] --> B["進捗率"]
C["残り量と予測速度"] --> D["残り時間の見積もり"]
E["必要な処理の成功"] --> F["処理全体の完了"]
図1: 割合・予測・結果は、同じ情報を言い換えたものではありません。
この記事では、測れる作業量の割合を進捗率、表示する棒を進捗バー、秒数の予測を残り時間の見積もりと呼び分けます。見積もりが出せなくても、測れた進捗まで分からなくなるわけではありません。
図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全9件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle
2. 「残り10秒」が「残り79秒」に増える計算
もっとも単純な残り時間の見積もりは、次の式です。
残り時間 ≒ 残りの作業量 ÷ これからの処理速度の見積もり
難しいのは割り算ではなく、これからの速度をまだ観測できないことです。そこで過去の速度を使って予測します。MicrosoftのRaymond Chenも、2004年のコピー時間に関する解説で、この未来を予測する難しさを説明しています。これは現在のWindowsの計算式を示す仕様書ではありません。2
総量1,000 MiBの仮想コピーを考えます。ここでMiBは1,048,576バイトです。まず一定速度80 MiB/sで2.5秒進み、その後の1秒だけ10 MiB/sに低下したとします。
| 観測時点 | 転送済み | 残り | 見積もりに使う速度 | 残り時間 |
|---|---|---|---|---|
| 開始から2.5秒 | 200 MiB | 800 MiB | 80 MiB/s | 800 ÷ 80 = 10秒 |
| 開始から3.5秒 | 210 MiB | 790 MiB | 10 MiB/s | 790 ÷ 10 = 79秒 |
1秒間で仕事は進んでいます。それでも、残りの仕事をこなす速度の予測が8分の1になったため、見積もりは長くなるのです。この例は直近の観測区間の速度をそのまま使っています。
flowchart TB
accTitle: 作業が進んでも残り時間が増える理由
accDescr: 残り量が減る効果よりも予測速度の低下が大きいと、計算される残り時間は増えます。
A["1秒間で10 MiB進む"] --> B["残り量は減る"]
C["予測速度が大きく低下"] --> D["残り時間は増え得る"]
B --> D
図2: 残り時間が増えたことと、処理が後戻りしたことは別です。
「残り1秒」も同じです。直前の速度なら1秒で済む量でも、次の処理が遅ければ1秒では終わりません。観測の間隔や秒数の丸め方も表示に影響します。ただし、いつまでも同じ数字なら正常だと決めつけず、後述する工程・画面更新・停止の切り分けが必要です。
3. 平均を取れば正確になるのか
速度の一瞬の変化を全部反映すると、数字が忙しく上下します。一方、開始時からの平均だけを使うと、最初に速かった影響が残り、その後の持続的な減速になかなか追いつきません。
この違いは、観測値の混ぜ方から説明できます。仮に過去の速度80と最新の速度10を半分ずつ混ぜれば、予測速度は45です。最新の10だけを使う場合より見積もりは滑らかになりますが、本当に10の状態が続くなら、しばらく楽観的になります。滑らかさと変化への追従は、同じ目標ではありません。
flowchart TB
accTitle: 速度をならすときのトレードオフ
accDescr: 最新の速度を重く見ると変化に敏感になり、過去の速度を重く見ると表示は滑らかでも変化への追従が遅くなります。
A["速度の観測値"] --> B["最新を重く見る"]
A --> C["過去を重く見る"]
B --> D["変化に敏感だが揺れる"]
C --> E["滑らかだが追従が遅い"]
図3: 数字が落ち着いていることと、予測が当たることは同義ではありません。
これは特定製品の実装ではなく、予測方法を考えるための例です。本記事の設計上の提案は、開始直後や工程の切り替え直後は無理に秒数を出さず、観測がそろってから「約1分」のように見積もりとして出すことです。根拠のない「あと1秒」を維持するより、残り時間を再計算中だと伝えるほうが誤解を減らせます。
4. 99個終わったのに、データ量では9.9%
次は速度ではなく、数える単位の問題です。100個のファイルがあり、最初の99個は各1 MiB、最後の1個は901 MiBだとします。合計は1,000 MiBです。
最初の99個が終わった時点では、件数なら99 ÷ 100 = 99%。しかしデータ量なら99 ÷ 1,000 = 9.9%です。残るファイルは1個でも、データの90.1%が残っています。どちらの計算も正しく、数えているものが違うだけです。
flowchart TB
accTitle: 最後の1ファイルが大きい場合
accDescr: 99個の小さいファイルの後に大きいファイルが残ると、件数の進捗とデータ量の進捗が大きくずれます。
A["99個の小さいファイル"] --> B["件数ではほぼ完了"]
C["最後に大きいファイル"] --> D["データ量は多く残る"]
B --> E["同じ処理でも表示が違う"]
D --> E
図4: 件数ベースの99%は、処理時間の残り1%を約束しません。
では、バイト数だけ見れば十分でしょうか。それも違います。SMBで小さいファイルを大量に送る場合は、ファイルの作成や要求の往復を何度も繰り返す負担があります。大きな1ファイルと同じ総バイト数でも、同じ時間にはなりません。3
このため、「残り500 MiB」という測定が正しくても、その500 MiBの内訳が変われば所要時間は変わり得ます。件数とバイト数を併記する価値は、どちらかが間違っているからではなく、互いに見えていない面を補えることにあります。
5. 「準備中」が長いのは、分母を探していることもある
割合を出すには、分母となる総量が要ります。しかし「フォルダー全体を処理する」と指示した瞬間に、その奥にある全ファイルを列挙し終えているとは限りません。
仮に100件あると思って80件まで処理し、その後さらに100件見つかったら、同じ80件でも80/100から80/200に変わります。表示は80%から40%に下がりますが、終えた仕事が消えたわけではありません。未確定の総量を確定値のように見せたことが、読者の期待とのずれを生みます。
flowchart TB
accTitle: 総量がまだ分からない段階の表示
accDescr: 対象を調べている間は割合を確定せず、総量が分かったら処理済み量と合わせて進捗率を表示します。
A["対象を調べる"] --> B{"総量が分かったか"}
B -->|"まだ"| C["工程名と発見件数を表示"]
B -->|"分かった"| D["割合を表示する"]
図5: 分母がない状態と、進捗が0%の状態は違います。
Windowsの進捗コントロールにも、値の分かる表示と、不明な間に動作中であることを示す表示があります。4 本記事なら、列挙中は「対象を確認中:1,200件を発見」と示し、総量が決まってから割合を出す設計を勧めます。残り秒数が出ないこと自体は、何もしていない証拠ではありません。
6. 「転送100%」と「全部終わった」は別の境界
6.1 最後に別の仕事が残っている
説明用に、アプリの処理を「転送 → 検証 → 結果を確定」の三段階に分けてみます。転送が終わっても、転送した内容の検証が必要な設計なら、処理全体は終わりません。これは一つのアプリの設計例で、すべてのコピーやインストールがこの順序だという意味ではありません。
flowchart TB
accTitle: 転送完了と処理全体の完了
accDescr: この仮想アプリでは転送の後に検証と結果の確定があり、転送済みバイト数だけでは全体の成功を判断しません。
A["転送"] --> B["検証"] --> C["結果を確定"] --> D["全体の成功"]
A -.-> E["転送100%はここまで"]
図6: 何の完了かを明示すれば、100%の後に別工程があっても説明できます。
ここで全体の棒を99%に固定して「残り1秒」と出し続けるより、「転送完了・検証中」と工程を切り替えて示すほうが筋が通ります。MicrosoftのデスクトップUIガイドも、実処理が終わる前に全体の完了を示さないよう求めています。5
6.2 書き込みの境界も一つではない
Windowsでは通常、ファイルの書き込みにキャッシュが使われます。アプリから書き込んだことと、記憶媒体への反映は、設定やAPIの条件によって境界が異なります。6 FlushFileBuffersは、指定したファイルのバッファ済み情報をデバイスへ送るためのAPIです。7
flowchart TB
accTitle: バッファを使う書き込みの概念図
accDescr: バッファを使う場合、アプリから受け付けた書き込みと記憶媒体側への反映を同じ出来事として扱わないようにします。
A["アプリから書き込み"] --> B["バッファに保持"] --> C["記憶媒体側へ反映"]
図7: この図はバッファを使う場合の概念図で、個々の製品の完了条件を表すものではありません。
ただし、「99%で止まる原因は必ずキャッシュの書き出し」とは言えません。 検証・書き出し・別の待機のどれかは、アプリの設計や記録を見て確認する必要があります。進捗の数字から、USBを抜いてよいか、電源を切ってよいかまで推測しないでください。
7. 本当に止まったのか、表示だけ止まったのか
WindowsのWPFアプリでは、UIスレッドのDispatcherが画面の仕事を処理します。そのスレッドを長時間占有すると、画面更新や入力への応答が遅れます。裏の処理と、その結果を画面に出す処理は分けて考える必要があります。8
flowchart TB
accTitle: 実処理と進捗表示の経路
accDescr: 実処理から進捗通知が出ても、UI側で更新を処理できなければ画面には反映されません。
A["実際の処理"] --> B["進捗を通知"] --> C["UI側で更新"] --> D["画面に反映"]
E["UIスレッドの詰まり"] -.-> C
図8: 表示の停止は、実処理の停止と同じとは限りません。
逆に、画面のアニメーションを実処理と独立して動かす設計なら、処理が待っていても丸い表示は回れます。「動いているから正常」「動かないから故障」という二択では足りません。
| 観察すること | 分かる手がかり | それだけでは断定できないこと |
|---|---|---|
| 処理済み件数・量・工程名の変化 | 報告された作業の進展 | 処理全体が最後まで成功するか |
| ログの時刻・対象・エラー | どこで何をしていると記録されたか | ログのない処理が停止しているか |
| 対象プロセスのCPU・ディスク・通信 | その時点の資源利用 | 正常進行か、待機か、無駄な反復か |
| 別ウィンドウの確認画面 | 利用者の操作待ちか | すべての停止原因 |
本記事で勧める順番は、まず画面と開始時刻を記録し、確認待ちがないかを調べ、件数やログが変わるかを比較することです。タスクマネージャーの値は補助証拠にとどめます。終了を検討する場合は、そのアプリのキャンセル手順と、途中の成果物がどう扱われるかを確認します。
.NETのキャンセルも、要求しただけで即座に処理を止める仕組みではなく、処理側が要求に応じる協調的な方式です。9 「キャンセルしています」と「キャンセル済み」を区別すべき理由もここにあります。万人に使える「何分たったら強制終了してよい」という数字は、この表示だけからは決められません。
8. 同じ処理を三つの表示で比べてみる
このデモは、ボタンで仮想処理の観測時点を進めます。時間を待つ必要はなく、ファイルの読み書きやアップロードも行いません。最初のケースは「99個の小さいファイルと1個の大きいファイル」です。同じ時点について、件数の棒、転送量の棒、処理全体の状態を並べています。
最後の大きいファイルを転送している途中では、件数の棒は99%のままでも転送量の棒は伸びます。転送量が100%になった時点では、全体の状態はまだ検証中です。次の時点に進めて、初めて成功になります。表示の違いだけで、同じ仕事が止まったようにも進んでいるようにも見えることを確かめられます。
flowchart TB
accTitle: 比較デモの読み方
accDescr: 同一の仮想処理の観測値を、件数、転送量、全体の状態という三つの表示に渡します。
A["一つの仮想処理"] --> B["同じ観測時点"]
B --> C["件数の割合"]
B --> D["転送量の割合"]
B --> E["処理全体の状態"]
図9: デモは三つの別処理ではなく、一つの処理の見せ方を比較しています。
もう一つのケースでは、2節の速度低下を再現し、10秒が79秒になる計算を表示します。使う計算は次のとおりです。これは学習用の単純な予測で、実用アプリの再試行・並列処理・工程別の予測まで実装したものではありません。
function estimateSeconds(remaining, rate) {
if (!Number.isFinite(remaining) || remaining < 0) return null;
if (remaining === 0) return 0;
if (!Number.isFinite(rate) || rate <= 0) return null;
const seconds = remaining / rate;
return Number.isFinite(seconds) ? seconds : null;
}
remainingとrateは、MiBとMiB/sなど単位をそろえて渡します。ここで0が返るのは見積もり対象の作業量が残っていないという意味であり、アプリ全体の成功を意味しません。残り量が正で、速度が0または不明ならnullにして、「残り0秒」と取り違えないようにします。
9. 作る側は「正確そう」より「誤解させない」を目指す
本記事なら、進捗の画面には、現在の工程、測れた作業量、根拠のある場合だけ残り時間、成功・失敗・キャンセルの結果を別々に持たせます。段階ごとの割合を一つに合成する場合も、「転送80%・検証20%」のような配分は設計上の重みであって、今回の時間配分の保証ではありません。
flowchart TB
accTitle: 観測値から進捗画面を組み立てる
accDescr: 現在の工程、測定した量、予測できるときの残り時間、最終結果を分けて表示します。
A["処理から得た情報"] --> B["現在の工程"]
A --> C["測れた量と総量"]
A --> D["条件がそろった見積もり"]
A --> E["成功・失敗・キャンセル"]
図10: 観測できたことと予測したことを、画面でも区別します。
たとえば「検証中:400 / 1,000件、残り時間は計算中」と表示できれば、秒数を出せなくても役立ちます。更新時刻を出すなら「最後に進捗が増えた時刻」と「画面が通信できた時刻」も別物です。後者だけを更新して正常に進んでいるように見せない設計にします。
アクセシビリティも同じ発想です。Webのprogress要素は、値を省略して進捗が不確定な状態を表せます。10 独自のARIA進捗表示でも、値が不明ならaria-valuenowを省略し、何の進捗かを分かる名前にします。11 見た目だけでなく、読み上げられる情報にも、分かっている範囲を正直に反映します。
10. よくある疑問
残り1秒なのに終わらないのは故障ですか?
表示だけでは決められません。見積もりの外れ、別工程、画面更新の遅れ、実際の停止を分けて確認します。「よくあるから大丈夫」と放置するのも、「1秒を超えたから故障」とするのも早計です。
99%なら残り時間も全体の1%ですか?
違います。割合の単位が件数でもバイトでも、その単位あたりの時間が一定とは限りません。全体の経過時間に1%を掛けて、残り時間を求めることはできません。
丸いアニメーションが動いていれば正常ですか?
動作中の表示と、実処理が進展した証拠は別です。処理済み量・工程・ログなどを組み合わせて見ます。アニメーションだけでは、正常終了まで進めることは保証されません。
残り時間が分からないなら、進捗バーも出せませんか?
総量と処理済み量が分かれば割合は出せます。予測の信頼性が低いときは秒数だけを省きます。総量自体が不明なら、不確定の表示と工程名・処理済み件数を使います。
11. まとめ:残り時間は予報、完了は結果
「残り1秒」が長いのは、コンピューターが1秒を数えられないからではありません。観測済みの作業量から、まだ起きていない処理時間を見積もっているからです。さらに、数える単位、対象の探索、最後の工程、画面更新の遅れが重なります。
flowchart TB
accTitle: 終わらない進捗表示を読む順番
accDescr: 何の割合か、速度の予測が変わったか、別工程か、表示や実処理が止まったかを順に確認します。
A["何の割合か"] --> B["予測速度は変わったか"] --> C["別工程が残っているか"] --> D["表示と実処理のどちらか"]
図11: 数字への不満を、確かめられる問いに分解します。
利用者は、数字だけでなく工程と変化を見る。開発者は、作業量・予測・結果を混ぜない。「あと1秒」を当て続けること以上に、今何が起きていて、何がまだ分からないのかを伝えることが、よい進捗表示の仕事です。
参考リンク
-
Microsoft Learn, LPPROGRESS_ROUTINE callback function. コピーの進捗コールバックが提供するバイト数の意味。 ↩
-
Microsoft, The Old New Thing, Why does the copy dialog give such horrible estimates?. 2004年の解説。現在のWindowsの内部実装仕様ではなく、未来の速度を予測する難しさの説明として参照。 ↩
-
Microsoft Learn, Slow SMB files transfer speed. 小さいファイルの転送で繰り返し発生するファイル作成・通信の負担。 ↩
-
Microsoft Learn, Progress controls. 進捗が確定できる場合と不確定な場合のコントロール。 ↩
-
Microsoft Learn, Progress Bars. デスクトップアプリの進捗表示に関する設計ガイド。 ↩
-
Microsoft Learn, File Caching. ファイルのキャッシュと書き込みの扱い。 ↩
-
Microsoft Learn, FlushFileBuffers function. ファイルのバッファ済み情報をデバイスへ送るAPI。 ↩
-
Microsoft Learn, Threading model. WPFのDispatcherとUIスレッドの応答性。 ↩
-
Microsoft Learn, Cancellation in Managed Threads. .NETの協調的キャンセル。 ↩
-
WHATWG, The progress element. HTMLの進捗要素と不確定状態。 ↩
-
W3C, WAI-ARIA 1.2: progressbar. 読み上げに渡す進捗の名前と値の規則。 ↩
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
同じ1GBなのに、動画1本より写真フォルダーのコピーが遅いのはなぜ?
Windowsで同じ容量なのにコピー時間が違う理由を図解します。ファイル数、SSDとNASの待ち時間、ZIPにまとめる効果、作成・転送・展開を含めた比較手順、robocopyの使いどころを整理します。
Windowsの「ハードウェアアクセラレータによるGPUスケジューリング」とは? オンにすると速くなる?
WindowsのハードウェアアクセラレータによるGPUスケジューリング(HAGS)を、一般ユーザー向けに図解します。仕組み、オン・オフの判断、設定が表示されない理由、フレーム生成との関係、安全な比較手順を整理します。
WPR/WPA実践 ── 「PC全体が重い」をシステム全体から調べる性能調査入門
「PC全体が重い」「起動が遅い」など、タスクマネージャーでは追えない性能問題は、OS全体のETWトレースを採って読むWPR/WPAで調べられます。wpr.exeでの採取手順から、WPAでのCPU・待ち時間・ディスクI/Oの読み方まで解説します。
WPFの高DPI対応 ── 「DPIに強いはず」なのにぼやける・にじむ原因と対処
WPFはSystem DPI Awareですが、DPIの違うモニターへ移すと全体がにじみ、ビットマップはぼやけます。原因の切り分け、Per-Monitor DPI対応、UseLayoutRoundingなど定番対処、WindowsFormsHost混在の罠まで整理します。
WinFormsの高DPI対応 ── 4Kモニターでぼやける・崩れる原因と現実的な対処
4KモニターでWinFormsアプリがぼやける・崩れる原因を、DPI仮想化とDPI認識モード(System Aware / Per-Monitor V2)から整理します。.NETと.NET Frameworkの設定方法、AutoScaleModeの罠まで解説します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
UI スレッド / タイマーテーマ
WPF / WinForms、UI スレッド、async/await、タイマー設計を整理するトピックです。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- 残り1秒のまま長時間動かないのは故障ですか?
- 表示だけでは判断できません。速度予測の外れ、最後の工程、更新されない画面、本当の停止を分けて確認します。処理件数やログの変化、確認待ちの画面などを調べ、残り1秒という数字だけで強制終了しないでください。
- 99%なら、残り時間も全体の1%ですか?
- いいえ。99%が件数・データ量・工程のどれを表すかで意味が変わり、それぞれの処理にかかる時間も同じではありません。進捗率は作業量の割合であり、残り時間そのものではありません。
- 丸いアニメーションが動いていれば処理は正常ですか?
- 正常に進んでいる証明にはなりません。画面のアニメーションと実際の処理が別に動く構成では、処理が待ち状態でもアニメーションは動けます。処理の進展を示す件数・工程・ログなどと区別します。
- 正確な残り時間を出せないなら進捗バーも出せませんか?
- 出せます。総量と処理済み量が分かれば割合を表示でき、速度が不安定なら残り時間だけを表示しない設計にできます。総量自体が不明なときは、割合を捏造せず、工程名や処理済み件数を表示します。