I know it's CPU intensive (sha256) but I want to know if it's possible to be
more faster and consume less memory (it consumes fewer memory)
it would be good if you could define what 'faster' and 'fewer memory'
mean here. it's easy to make your program faster, it's also possible
to make it generate less garbage (resulting in a smaller memory
footprint) but it's hard to do both, especially if you set your
targets too ambitiously. that said:
- please use gofmt to make your code easier on the eyes.
- you're not really using any of the concurrency primitives available
in Go. sha256 calculation is cpu-bound, therefore you would do good to
do more than one calculation at the same time. for that you may want
to spin goroutines (or hand off work to previously spun goroutines)
that independently calculate the hash for each file, then send the
result to a collector goroutine
it would help if we put it in perspective using the Go tree:
- on my machine your code takes 4 seconds to hash all 12323 files (by
the way, it reports that it has hashed 12324, but only 12323 appear in
the output log)
- your code takes, at maximum, 3.8MB of memory to do the job (as
reported by /usr/bin/time -l on OSX):
$ /usr/bin/time -l ./t -path=/Users/aam/go
Find Duplicated Files: Go Walk Hash Calculation...
* Pattern: *
* Route: /Users/aam/go
* Output filename: ./output.json
Written 12324 entries.
3.70 real 2.51 user 1.18 sys
3776512 maximum resident set size
- if you _only_ changed the buffer size on line 65 to something larger
than 100 (8192 for example) that time drops to 2.5 seconds with only
marginal memory consumption increase (you're much better off if you
use io.Copy instead of doing this for loop by yourself, by the way):
$ /usr/bin/time -l ./t -path=/Users/aam/go
Find Duplicated Files: Go Walk Hash Calculation...
* Pattern: *
* Route: /Users/aam/go
* Output filename: ./output.json
Written 12324 entries.
2.49 real 1.96 user 0.33 sys
3981312 maximum resident set size
from here on your best bet is using the concurrency primitives in Go.
I wrote a similar program for a different purpose and banged it into
shape just now to illustrate the benefits of concurrency. the program
is here:
http://mirtchovski.com/go/sha256.go. it allows you to vary
the number of OS threads used, as well as the number of worker
goroutines that read files. in its default form (1 worker, 1 cpu) it
takes 2.2 seconds and 4.3MB of memory:
$ /usr/bin/time -l ./sha256 -workers=1 -cpus 1 ~/go > /dev/null
2013/07/16 10:24:05 starting...
2013/07/16 10:24:07 completed in 2.11673696s. 12323 hashed.
2.12 real 1.91 user 0.21 sys
4300800 maximum resident set size
however when we crank up the concurrency to 16 workers on 8 cpus we
lower the time taken to 0.65 seconds at the expense of 7MB memory
footprint:
$ /usr/bin/time -l ./sha256 -workers=16 -cpus=8 ~/go > /dev/null
2013/07/16 10:28:17 starting...
2013/07/16 10:28:18 completed in 646.008192ms. 12323 hashed.
0.65 real 3.55 user 0.43 sys
7094272 maximum resident set size
hope this helps,
andrey
NB: all timings are done on hot caches