diff --git a/learn_go_with_tests/concurrency/CheckWebsites.go b/learn_go_with_tests/concurrency/CheckWebsites.go index 9438de0..1fbbfda 100644 --- a/learn_go_with_tests/concurrency/CheckWebsites.go +++ b/learn_go_with_tests/concurrency/CheckWebsites.go @@ -1,12 +1,33 @@ package concurrency type WebsiteChecker func(string) bool +type result struct { + string + bool +} func CheckWebsites(wc WebsiteChecker, urls []string) map[string]bool { results := make(map[string]bool) + resultChannel := make(chan result) for _, url := range urls { - results[url] = wc(url) + // anonymous function call required because go routines must call + // a function to start. An anonymous function maintains access to + // the lexical scope in which they are defined - all the variables + // that are available at the point when you declare the anonymous + //function are also available in the body of the function. + // url := url // create a new variable to avoid capturing the loop variable. + // go func() { + // results[url] = wc(url) + // }() + go func(u string) { + resultChannel <- result{u, wc(u)} // send statement + }(url) // or just pass by value to give the func it's own url + } + + for i := 0; i < len(urls); i++ { + r := <-resultChannel // receive statement + results[r.string] = r.bool } return results diff --git a/learn_go_with_tests/concurrency/CheckWebsites_test.go b/learn_go_with_tests/concurrency/CheckWebsites_test.go index 9a4ca69..be58d15 100644 --- a/learn_go_with_tests/concurrency/CheckWebsites_test.go +++ b/learn_go_with_tests/concurrency/CheckWebsites_test.go @@ -3,12 +3,30 @@ package concurrency import ( "reflect" "testing" + "time" ) func mockWebsiteChecker(url string) bool { return url != "waat://furhurterwe.geds" } +func slowStubWebsiteChecker(_ string) bool { + time.Sleep(20 * time.Millisecond) + return true +} + +// What does testing.B do? +func BenchmarkCheckWebsites(b *testing.B) { + urls := make([]string, 100) + for i := 0; i < len(urls); i++ { + urls[i] = "a url" + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + CheckWebsites(slowStubWebsiteChecker, urls) + } +} + func TestWebsites(t *testing.T) { websites := []string{ "http://google.com", diff --git a/learn_go_with_tests/concurrency/READMD.md b/learn_go_with_tests/concurrency/READMD.md new file mode 100644 index 0000000..5efa9ec --- /dev/null +++ b/learn_go_with_tests/concurrency/READMD.md @@ -0,0 +1,9 @@ +# Concurrency + +https://quii.gitbook.io/learn-go-with-tests/go-fundamentals/concurrency + +This was an interesting chapter. The high-level takeaways: + +- An anonymous function maintains access to the lexical scope in which they are defined +- Go can help identify race conditions with [race detector](https://blog.golang.org/race-detector) `go test -race` +- Coordinating go routines can be accomplished with channels. Channels are a data structure that can both receive and send values. This allows cross go routine communication. Channels have a type, and you will commonly see structs passed around. \ No newline at end of file