Fix extraction speed and UI label updates
- Change OS priority from IDLE/BELOW_NORMAL to NORMAL/BELOW_NORMAL so extraction runs at full speed (matching manual 7-Zip/WinRAR performance) - Use "high" priority in both hybrid and full extraction paths - Increase hybrid extraction threads from hardcoded 2 to dynamic calculation (half CPU count, min 2, max 8) - Fix emitState forced emit being silently dropped when a non-forced timer was already pending — forced emits now always replace pending timers to ensure immediate UI feedback during extraction transitions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
375ec36781
commit
1cda391dfe
@ -3570,14 +3570,16 @@ export class DownloadManager extends EventEmitter {
|
|||||||
this.emit("state", this.getSnapshot());
|
this.emit("state", this.getSnapshot());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Too soon — schedule deferred forced emit
|
// Too soon — replace any pending timer with a shorter forced-emit timer
|
||||||
if (!this.stateEmitTimer) {
|
if (this.stateEmitTimer) {
|
||||||
|
clearTimeout(this.stateEmitTimer);
|
||||||
|
this.stateEmitTimer = null;
|
||||||
|
}
|
||||||
this.stateEmitTimer = setTimeout(() => {
|
this.stateEmitTimer = setTimeout(() => {
|
||||||
this.stateEmitTimer = null;
|
this.stateEmitTimer = null;
|
||||||
this.lastStateEmitAt = nowMs();
|
this.lastStateEmitAt = nowMs();
|
||||||
this.emit("state", this.getSnapshot());
|
this.emit("state", this.getSnapshot());
|
||||||
}, MIN_FORCE_GAP_MS - sinceLastEmit);
|
}, MIN_FORCE_GAP_MS - sinceLastEmit);
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.stateEmitTimer) {
|
if (this.stateEmitTimer) {
|
||||||
@ -6400,7 +6402,7 @@ export class DownloadManager extends EventEmitter {
|
|||||||
packageId,
|
packageId,
|
||||||
hybridMode: true,
|
hybridMode: true,
|
||||||
maxParallel: this.settings.maxParallelExtract || 2,
|
maxParallel: this.settings.maxParallelExtract || 2,
|
||||||
extractCpuPriority: this.settings.extractCpuPriority,
|
extractCpuPriority: "high",
|
||||||
onProgress: (progress) => {
|
onProgress: (progress) => {
|
||||||
if (progress.phase === "preparing") {
|
if (progress.phase === "preparing") {
|
||||||
pkg.postProcessLabel = progress.archiveName || "Vorbereiten...";
|
pkg.postProcessLabel = progress.archiveName || "Vorbereiten...";
|
||||||
@ -6762,8 +6764,8 @@ export class DownloadManager extends EventEmitter {
|
|||||||
packageId,
|
packageId,
|
||||||
skipPostCleanup: true,
|
skipPostCleanup: true,
|
||||||
maxParallel: this.settings.maxParallelExtract || 2,
|
maxParallel: this.settings.maxParallelExtract || 2,
|
||||||
// All downloads finished — use highest configured priority so extraction
|
// All downloads finished — use NORMAL OS priority so extraction runs at
|
||||||
// isn't starved. "high" maps to BELOW_NORMAL instead of the default IDLE.
|
// full speed (matching manual 7-Zip/WinRAR speed).
|
||||||
extractCpuPriority: "high",
|
extractCpuPriority: "high",
|
||||||
onProgress: (progress) => {
|
onProgress: (progress) => {
|
||||||
if (progress.phase === "preparing") {
|
if (progress.phase === "preparing") {
|
||||||
|
|||||||
@ -600,8 +600,8 @@ function extractCpuBudgetFromPriority(priority?: string): number {
|
|||||||
|
|
||||||
function extractOsPriority(priority?: string): number {
|
function extractOsPriority(priority?: string): number {
|
||||||
switch (priority) {
|
switch (priority) {
|
||||||
case "high": return os.constants.priority.PRIORITY_BELOW_NORMAL;
|
case "high": return os.constants.priority.PRIORITY_NORMAL;
|
||||||
default: return os.constants.priority.PRIORITY_LOW;
|
default: return os.constants.priority.PRIORITY_BELOW_NORMAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,10 +615,15 @@ function extractCpuBudgetPercent(priority?: string): number {
|
|||||||
|
|
||||||
function extractorThreadSwitch(hybridMode = false, priority?: string): string {
|
function extractorThreadSwitch(hybridMode = false, priority?: string): string {
|
||||||
if (hybridMode) {
|
if (hybridMode) {
|
||||||
// 2 threads during hybrid extraction (download + extract simultaneously).
|
// Use half the CPU budget during hybrid extraction to leave headroom for
|
||||||
// JDownloader 2 uses in-process 7-Zip-JBinding which naturally limits throughput
|
// concurrent downloads. Falls back to at least 2 threads.
|
||||||
// to ~16 MB/s write. 2 UnRAR threads produce similar controlled disk load.
|
const envValue = Number(process.env.RD_EXTRACT_THREADS ?? NaN);
|
||||||
return "-mt2";
|
if (Number.isFinite(envValue) && envValue >= 1 && envValue <= 32) {
|
||||||
|
return `-mt${Math.floor(envValue)}`;
|
||||||
|
}
|
||||||
|
const cpuCount = Math.max(1, os.cpus().length || 1);
|
||||||
|
const hybridThreads = Math.max(2, Math.min(8, Math.floor(cpuCount / 2)));
|
||||||
|
return `-mt${hybridThreads}`;
|
||||||
}
|
}
|
||||||
const envValue = Number(process.env.RD_EXTRACT_THREADS ?? NaN);
|
const envValue = Number(process.env.RD_EXTRACT_THREADS ?? NaN);
|
||||||
if (Number.isFinite(envValue) && envValue >= 1 && envValue <= 32) {
|
if (Number.isFinite(envValue) && envValue >= 1 && envValue <= 32) {
|
||||||
@ -640,8 +645,8 @@ function lowerExtractProcessPriority(childPid: number | undefined, cpuPriority?:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Lowers CPU scheduling priority so extraction doesn't starve other processes.
|
// Sets CPU scheduling priority for the extraction process.
|
||||||
// high → BELOW_NORMAL, middle/low → IDLE. I/O priority stays Normal (like JDownloader 2).
|
// high → NORMAL (full speed), default → BELOW_NORMAL. I/O priority stays Normal.
|
||||||
os.setPriority(pid, extractOsPriority(cpuPriority));
|
os.setPriority(pid, extractOsPriority(cpuPriority));
|
||||||
} catch {
|
} catch {
|
||||||
// ignore: priority lowering is best-effort
|
// ignore: priority lowering is best-effort
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user