Add option to disable parallel file processing (#695)
Fixes #685. Fixes #572. Also fixes #690 by using "logical CPUs".
This commit is contained in:
parent
d168fffb12
commit
a44ba5f88b
2 changed files with 52 additions and 28 deletions
21
src/cli.rs
21
src/cli.rs
|
|
@ -350,16 +350,31 @@ timeout before each transformation or compression trial, and will stop trying to
|
||||||
the file if the timeout is exceeded. Note that this does not cut short any operations that \
|
the file if the timeout is exceeded. Note that this does not cut short any operations that \
|
||||||
are already in progress, so it is currently of limited effectiveness for large files with \
|
are already in progress, so it is currently of limited effectiveness for large files with \
|
||||||
high compression levels.")
|
high compression levels.")
|
||||||
.value_name("secs")
|
|
||||||
.long("timeout")
|
.long("timeout")
|
||||||
|
.value_name("secs")
|
||||||
.value_parser(value_parser!(u64)),
|
.value_parser(value_parser!(u64)),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("threads")
|
Arg::new("threads")
|
||||||
.help("Set number of threads to use [default: num CPU cores]")
|
.help("Number of threads to use [default: num logical CPUs]")
|
||||||
.long("threads")
|
.long_help("\
|
||||||
|
Set the maximum number of threads to use. Oxipng uses multithreading to evaluate multiple \
|
||||||
|
optimizations on the same file in parallel as well as process multiple files in parallel. \
|
||||||
|
You can set this to a lower value if you need to limit memory or CPU usage.
|
||||||
|
|
||||||
|
[default: num logical CPUs]")
|
||||||
.short('t')
|
.short('t')
|
||||||
|
.long("threads")
|
||||||
.value_name("num")
|
.value_name("num")
|
||||||
.value_parser(value_parser!(usize)),
|
.value_parser(value_parser!(usize)),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("parallel-files")
|
||||||
|
.help("Process multiple files sequentially")
|
||||||
|
.long_help("\
|
||||||
|
Process multiple files sequentially rather than in parallel. Use this if you need \
|
||||||
|
determinism in the processing order. Note this is not necessary if using '--threads 1'.")
|
||||||
|
.long("sequential")
|
||||||
|
.action(ArgAction::SetFalse),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
59
src/main.rs
59
src/main.rs
|
|
@ -72,32 +72,20 @@ fn main() -> ExitCode {
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
let summary = files
|
let parallel_files = matches.get_flag("parallel-files");
|
||||||
.into_par_iter()
|
let summary = if parallel_files {
|
||||||
.map(|(input, output)| {
|
files
|
||||||
match oxipng::optimize(&input, &output, &opts) {
|
.into_par_iter()
|
||||||
// For optimizing single files, this will return the correct exit code always.
|
.map(|(input, output)| process_file(&input, &output, &opts))
|
||||||
// For recursive optimization, the correct choice is a bit subjective.
|
.min()
|
||||||
// We're choosing to return a 0 exit code if ANY file in the set
|
} else {
|
||||||
// runs correctly.
|
files
|
||||||
// The reason for this is that recursion may pick up files that are not
|
.into_iter()
|
||||||
// PNG files, and return an error for them.
|
.map(|(input, output)| process_file(&input, &output, &opts))
|
||||||
// We don't really want to return an error code for those files.
|
.min()
|
||||||
Ok(_) => OptimizationResult::Ok,
|
};
|
||||||
Err(e @ PngError::C2PAMetadataPreventsChanges) => {
|
|
||||||
warn!("{input}: {e}");
|
|
||||||
OptimizationResult::Skipped
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error!("{input}: {e}");
|
|
||||||
OptimizationResult::Failed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.min()
|
|
||||||
.unwrap_or(OptimizationResult::Skipped);
|
|
||||||
|
|
||||||
match summary {
|
match summary.unwrap_or(OptimizationResult::Skipped) {
|
||||||
OptimizationResult::Ok => ExitCode::SUCCESS,
|
OptimizationResult::Ok => ExitCode::SUCCESS,
|
||||||
OptimizationResult::Failed => ExitCode::FAILURE,
|
OptimizationResult::Failed => ExitCode::FAILURE,
|
||||||
OptimizationResult::Skipped => ExitCode::from(3),
|
OptimizationResult::Skipped => ExitCode::from(3),
|
||||||
|
|
@ -421,3 +409,24 @@ fn parse_numeric_range_opts(
|
||||||
|
|
||||||
Err(ERROR_MESSAGE.to_owned())
|
Err(ERROR_MESSAGE.to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_file(input: &InFile, output: &OutFile, opts: &Options) -> OptimizationResult {
|
||||||
|
match oxipng::optimize(input, output, opts) {
|
||||||
|
// For optimizing single files, this will return the correct exit code always.
|
||||||
|
// For recursive optimization, the correct choice is a bit subjective.
|
||||||
|
// We're choosing to return a 0 exit code if ANY file in the set
|
||||||
|
// runs correctly.
|
||||||
|
// The reason for this is that recursion may pick up files that are not
|
||||||
|
// PNG files, and return an error for them.
|
||||||
|
// We don't really want to return an error code for those files.
|
||||||
|
Ok(_) => OptimizationResult::Ok,
|
||||||
|
Err(e @ PngError::C2PAMetadataPreventsChanges) => {
|
||||||
|
warn!("{input}: {e}");
|
||||||
|
OptimizationResult::Skipped
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("{input}: {e}");
|
||||||
|
OptimizationResult::Failed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue