diff --git a/CHANGELOG.md b/CHANGELOG.md index 9438983..b8af0f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog -## [dev] +## [0.2.0] + +- Add threaded option (`-t`) to use all CPU cores + + +## [0.1.0] - Switch to go mods - go (>= 1.11 required) - Switch to axllent/semver for app updating diff --git a/README.md b/README.md index 9b8f044..b162f5a 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Options: -m, --max string downscale to a maximum width & height in pixels (x) -o, --out string output directory (default overwrites original) -p, --preserve preserve file modification times (default true) + -t, --threaded run multi-threaded (use all CPU cores) -u, --update update to latest release -v, --version show version number -h, --help show help diff --git a/main.go b/main.go index a67d2bd..b906011 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,9 @@ import ( "os" "os/exec" "regexp" + "runtime" "strconv" + "sync" "github.com/axllent/ghru" "github.com/spf13/pflag" @@ -22,6 +24,7 @@ var ( optipng string pngquant string gifsicle string + threads = 1 version = "dev" ) @@ -51,13 +54,14 @@ func main() { } var maxSizes string - var update, showversion, showhelp bool + var multiThreaded, update, showversion, showhelp bool flag.IntVarP(&quality, "quality", "q", 75, "quality, JPEG only") flag.StringVarP(&maxSizes, "max", "m", "", "downscale to a maximum width & height in pixels (x)") flag.StringVarP(&outputDir, "out", "o", "", "output directory (default overwrites original)") flag.BoolVarP(&preserveModTimes, "preserve", "p", true, "preserve file modification times") flag.BoolVarP(&update, "update", "u", false, "update to latest release") + flag.BoolVarP(&multiThreaded, "threaded", "t", false, "run multi-threaded (use all CPU cores)") flag.BoolVarP(&showversion, "version", "v", false, "show version number") flag.BoolVarP(&showhelp, "help", "h", false, "show help") @@ -137,9 +141,34 @@ func main() { } } - for _, img := range args { - Goptimize(img) + if multiThreaded { + threads = runtime.NumCPU() } + + processChan := make(chan string) + + wg := &sync.WaitGroup{} // Signal to main goroutine that worker goroutines are working/done working + wg.Add(threads) + + for i := 0; i < threads; i++ { + go func() { + for nextFile := range processChan { + Goptimize(nextFile) + } + // Channel was closed, so we finished this goroutine. + wg.Done() // Let main goroutine know we are done. + }() + } + + for _, img := range args { + processChan <- img + } + + // Close the channel. This tells the worker goroutines that they can be done. + close(processChan) + + // Wait for all worker goroutines to finish processing the IPs + wg.Wait() } // displayDelectedOptimizer prints whether the optimizer was found