Created
March 24, 2021 13:49
-
-
Save jvkersch/150fb99b438ecab246ecdedfd3b47d05 to your computer and use it in GitHub Desktop.
CSP example from chapter 8 in The Go Programming Language
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"os" | |
"path/filepath" | |
) | |
// walkDir recursively walks the file tree rooted at dir | |
// and sends the size of each found file on fileSizes. | |
func walkDir(dir string, fileSizes chan<- int64) { | |
for _, entry := range dirents(dir) { | |
if entry.IsDir() { | |
subdir := filepath.Join(dir, entry.Name()) | |
walkDir(subdir, fileSizes) | |
} else { | |
fileSizes <- entry.Size() | |
} | |
} | |
} | |
// dirents returns the entries of directory dir | |
func dirents(dir string) []os.FileInfo { | |
entries, err := ioutil.ReadDir(dir) | |
if err != nil { | |
fmt.Fprintf(os.Stderr, "du: %v\n", err) | |
return nil | |
} | |
return entries | |
} | |
func main() { | |
// Determine which directories to traverse | |
flag.Parse() | |
roots := flag.Args() | |
if len(roots) == 0 { | |
roots = []string{"."} | |
} | |
// Traverse the file tree | |
fileSizes := make(chan int64) | |
go func() { | |
for _, root := range roots { | |
walkDir(root, fileSizes) | |
} | |
close(fileSizes) | |
}() | |
// Print the results. | |
var nfiles, nbytes int64 | |
for size := range fileSizes { | |
nfiles++ | |
nbytes += size | |
} | |
printDiskUsage(nfiles, nbytes) // final totals | |
} | |
func printDiskUsage(nfiles, nbytes int64) { | |
fmt.Printf("%d files, %.1f GB\n", nfiles, float64(nbytes)/1e9) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"os" | |
"path/filepath" | |
"time" | |
) | |
// walkDir recursively walks the file tree rooted at dir | |
// and sends the size of each found file on fileSizes. | |
func walkDir(dir string, fileSizes chan<- int64) { | |
for _, entry := range dirents(dir) { | |
if entry.IsDir() { | |
subdir := filepath.Join(dir, entry.Name()) | |
walkDir(subdir, fileSizes) | |
} else { | |
fileSizes <- entry.Size() | |
} | |
} | |
} | |
// dirents returns the entries of directory dir | |
func dirents(dir string) []os.FileInfo { | |
entries, err := ioutil.ReadDir(dir) | |
if err != nil { | |
fmt.Fprintf(os.Stderr, "du: %v\n", err) | |
return nil | |
} | |
return entries | |
} | |
func main() { | |
// Determine which directories to traverse | |
flag.Parse() | |
roots := flag.Args() | |
if len(roots) == 0 { | |
roots = []string{"."} | |
} | |
// Traverse the file tree | |
fileSizes := make(chan int64) | |
go func() { | |
for _, root := range roots { | |
walkDir(root, fileSizes) | |
} | |
close(fileSizes) | |
}() | |
// Generate a tick every 500ms | |
tick := time.Tick(500 * time.Millisecond) | |
var nfiles, nbytes int64 | |
loop: | |
for { | |
select { | |
case size, ok := <-fileSizes: | |
if !ok { | |
break loop // fileSizes was closed | |
} | |
nfiles++ | |
nbytes += size | |
case <-tick: | |
printDiskUsage(nfiles, nbytes) | |
} | |
} | |
printDiskUsage(nfiles, nbytes) // final totals | |
} | |
func printDiskUsage(nfiles, nbytes int64) { | |
fmt.Printf("%d files, %.1f GB\n", nfiles, float64(nbytes)/1e9) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"os" | |
"path/filepath" | |
"sync" | |
"time" | |
) | |
// walkDir recursively walks the file tree rooted at dir | |
// and sends the size of each found file on fileSizes. | |
func walkDir(dir string, n *sync.WaitGroup, fileSizes chan<- int64) { | |
defer n.Done() | |
for _, entry := range dirents(dir) { | |
if entry.IsDir() { | |
n.Add(1) | |
subdir := filepath.Join(dir, entry.Name()) | |
go walkDir(subdir, n, fileSizes) | |
} else { | |
fileSizes <- entry.Size() | |
} | |
} | |
} | |
// dirents returns the entries of directory dir | |
func dirents(dir string) []os.FileInfo { | |
entries, err := ioutil.ReadDir(dir) | |
if err != nil { | |
fmt.Fprintf(os.Stderr, "du: %v\n", err) | |
return nil | |
} | |
return entries | |
} | |
func main() { | |
// Determine which directories to traverse | |
flag.Parse() | |
roots := flag.Args() | |
if len(roots) == 0 { | |
roots = []string{"."} | |
} | |
// Traverse the file tree | |
fileSizes := make(chan int64) | |
var n sync.WaitGroup | |
for _, root := range roots { | |
n.Add(1) | |
go walkDir(root, &n, fileSizes) | |
} | |
go func() { | |
n.Wait() | |
close(fileSizes) | |
}() | |
// Generate a tick every 500ms | |
tick := time.Tick(500 * time.Millisecond) | |
var nfiles, nbytes int64 | |
loop: | |
for { | |
select { | |
case size, ok := <-fileSizes: | |
if !ok { | |
break loop // fileSizes was closed | |
} | |
nfiles++ | |
nbytes += size | |
case <-tick: | |
printDiskUsage(nfiles, nbytes) | |
} | |
} | |
printDiskUsage(nfiles, nbytes) // final totals | |
} | |
func printDiskUsage(nfiles, nbytes int64) { | |
fmt.Printf("%d files, %.1f GB\n", nfiles, float64(nbytes)/1e9) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"os" | |
"path/filepath" | |
"sync" | |
"time" | |
) | |
// walkDir recursively walks the file tree rooted at dir | |
// and sends the size of each found file on fileSizes. | |
func walkDir(dir string, n *sync.WaitGroup, fileSizes chan<- int64) { | |
defer n.Done() | |
for _, entry := range dirents(dir) { | |
if entry.IsDir() { | |
n.Add(1) | |
subdir := filepath.Join(dir, entry.Name()) | |
go walkDir(subdir, n, fileSizes) | |
} else { | |
fileSizes <- entry.Size() | |
} | |
} | |
} | |
// counting semaphore for limiting concurrency in dirents | |
var sema = make(chan struct{}, 20) | |
// dirents returns the entries of directory dir | |
func dirents(dir string) []os.FileInfo { | |
sema <- struct{}{} // acquire token | |
defer func() { <-sema }() // eventually release token | |
entries, err := ioutil.ReadDir(dir) | |
if err != nil { | |
fmt.Fprintf(os.Stderr, "du: %v\n", err) | |
return nil | |
} | |
return entries | |
} | |
func main() { | |
// Determine which directories to traverse | |
flag.Parse() | |
roots := flag.Args() | |
if len(roots) == 0 { | |
roots = []string{"."} | |
} | |
// Traverse the file tree | |
fileSizes := make(chan int64) | |
var n sync.WaitGroup | |
for _, root := range roots { | |
n.Add(1) | |
go walkDir(root, &n, fileSizes) | |
} | |
go func() { | |
n.Wait() | |
close(fileSizes) | |
}() | |
// Generate a tick every 500ms | |
tick := time.Tick(500 * time.Millisecond) | |
var nfiles, nbytes int64 | |
loop: | |
for { | |
select { | |
case size, ok := <-fileSizes: | |
if !ok { | |
break loop // fileSizes was closed | |
} | |
nfiles++ | |
nbytes += size | |
case <-tick: | |
printDiskUsage(nfiles, nbytes) | |
} | |
} | |
printDiskUsage(nfiles, nbytes) // final totals | |
} | |
func printDiskUsage(nfiles, nbytes int64) { | |
fmt.Printf("%d files, %.1f GB\n", nfiles, float64(nbytes)/1e9) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment