diff --git a/.gitignore b/.gitignore index 485dee6..090a1f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea +.DS_Store diff --git a/01-intro-solution/02-join/01-join/main.go b/01-intro-solution/01-goroutines/03-join/main.go similarity index 100% rename from 01-intro-solution/02-join/01-join/main.go rename to 01-intro-solution/01-goroutines/03-join/main.go diff --git a/01-intro/02-join/03-add/counting/count.go b/01-intro-solution/01-goroutines/04-add/counting/count.go similarity index 82% rename from 01-intro/02-join/03-add/counting/count.go rename to 01-intro-solution/01-goroutines/04-add/counting/count.go index d074b67..ccd1f32 100644 --- a/01-intro/02-join/03-add/counting/count.go +++ b/01-intro-solution/01-goroutines/04-add/counting/count.go @@ -12,6 +12,16 @@ func init() { rand.Seed(time.Now().UnixNano()) } +// GenerateNumbers - random number generation +func GenerateNumbers(max int) []int { + rand.Seed(time.Now().UnixNano()) + numbers := make([]int, max) + for i := 0; i < max; i++ { + numbers[i] = rand.Intn(10) + } + return numbers +} + // Add - sequential code to add numbers func Add(numbers []int) int64 { var sum int64 diff --git a/01-intro/02-join/03-add/counting/count_test.go b/01-intro-solution/01-goroutines/04-add/counting/count_test.go similarity index 50% rename from 01-intro/02-join/03-add/counting/count_test.go rename to 01-intro-solution/01-goroutines/04-add/counting/count_test.go index 67cf939..e46f31b 100644 --- a/01-intro/02-join/03-add/counting/count_test.go +++ b/01-intro-solution/01-goroutines/04-add/counting/count_test.go @@ -1,27 +1,18 @@ package counting import ( - "math/rand" "testing" ) -func generateNumbers(max int) []int { - numbers := make([]int, max) - for i := 0; i < max; i++ { - numbers[i] = rand.Intn(10) - } - return numbers -} - func BenchmarkAdd(b *testing.B) { - numbers := generateNumbers(1e7) + numbers := GenerateNumbers(1e7) for i := 0; i < b.N; i++ { Add(numbers) } } func BenchmarkAddConcurrent(b *testing.B) { - numbers := generateNumbers(1e7) + numbers := GenerateNumbers(1e7) for i := 0; i < b.N; i++ { AddConcurrent(numbers) } diff --git a/01-intro-solution/01-goroutines/04-add/main.go b/01-intro-solution/01-goroutines/04-add/main.go new file mode 100644 index 0000000..70874d5 --- /dev/null +++ b/01-intro-solution/01-goroutines/04-add/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "fmt" + "time" + + "github.com/andcloudio/go-concurrency-exercises/01-intro/01-goroutines/04-add/counting" +) + +func main() { + numbers := counting.GenerateNumbers(1e7) + + t := time.Now() + _ = counting.Add(numbers) + fmt.Printf("Sequential Add took: %s\n", time.Since(t)) + + t = time.Now() + _ = counting.AddConcurrent(numbers) + fmt.Printf("Concurrent Add took: %s\n", time.Since(t)) +} diff --git a/01-intro-solution/03-closure/01-closure/main.go b/01-intro-solution/01-goroutines/05-closure/main.go similarity index 73% rename from 01-intro-solution/03-closure/01-closure/main.go rename to 01-intro-solution/01-goroutines/05-closure/main.go index 5cb151f..7d05723 100644 --- a/01-intro-solution/03-closure/01-closure/main.go +++ b/01-intro-solution/01-goroutines/05-closure/main.go @@ -5,7 +5,7 @@ import ( "sync" ) -//TODO: run the program and check that variable i +// run the program and check that variable i // was pinned for access from goroutine even after // enclosing function returns. @@ -18,8 +18,9 @@ func main() { go func() { defer wg.Done() i++ - fmt.Println(i) + fmt.Printf("value of i: %v\n", i) }() + fmt.Println("return from function") return } diff --git a/01-intro-solution/03-closure/02-closure/main.go b/01-intro-solution/01-goroutines/06-closure/main.go similarity index 70% rename from 01-intro-solution/03-closure/02-closure/main.go rename to 01-intro-solution/01-goroutines/06-closure/main.go index 5225945..32f3b39 100644 --- a/01-intro-solution/03-closure/02-closure/main.go +++ b/01-intro-solution/01-goroutines/06-closure/main.go @@ -9,14 +9,14 @@ func main() { var wg sync.WaitGroup // what is the output - //TODO: fix the issue. + // fix the issue. - for i := 0; i < 3; i++ { + for i := 1; i <= 3; i++ { wg.Add(1) - go func() { + go func(i int) { defer wg.Done() fmt.Println(i) - }() + }(i) } wg.Wait() } diff --git a/01-intro-solution/02-channel/01-channel/main.go b/01-intro-solution/02-channel/01-channel/main.go new file mode 100644 index 0000000..edcc518 --- /dev/null +++ b/01-intro-solution/02-channel/01-channel/main.go @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func main() { + ch := make(chan int) + + go func(a, b int) { + c := a + b + ch <- c + }(1, 2) + // get the value computed from goroutine + c := <-ch + fmt.Printf("computed value %v\n", c) +} diff --git a/01-intro-solution/02-channel/02-channel/main.go b/01-intro-solution/02-channel/02-channel/main.go new file mode 100644 index 0000000..ff9d595 --- /dev/null +++ b/01-intro-solution/02-channel/02-channel/main.go @@ -0,0 +1,18 @@ +package main + +import "fmt" + +func main() { + ch := make(chan int) + go func() { + for i := 0; i < 6; i++ { + // send iterator over channel + ch <- i + } + close(ch) + }() + // range over channel to recv values + for i := range ch { + fmt.Println(i) + } +} diff --git a/01-intro/04-channel/03-channel/main.go b/01-intro-solution/02-channel/03-channel/main.go similarity index 72% rename from 01-intro/04-channel/03-channel/main.go rename to 01-intro-solution/02-channel/03-channel/main.go index 2b4cd1e..f3d8a25 100644 --- a/01-intro/04-channel/03-channel/main.go +++ b/01-intro-solution/02-channel/03-channel/main.go @@ -5,12 +5,12 @@ import ( ) func main() { - ch := make(chan int) + ch := make(chan int, 6) go func() { defer close(ch) - // TODO: send all iterator values on channel without blocking + // send all iterator values on channel without blocking for i := 0; i < 6; i++ { fmt.Printf("Sending: %d\n", i) ch <- i diff --git a/01-intro-solution/02-channel/04-channel/main.go b/01-intro-solution/02-channel/04-channel/main.go new file mode 100644 index 0000000..f1c0e89 --- /dev/null +++ b/01-intro-solution/02-channel/04-channel/main.go @@ -0,0 +1,33 @@ +package main + +import "fmt" + +// TODO: Implement ping pong with Channel Direction + +func ping(out chan<- string) { + // send message on ch1 + out <- "ping" +} + +func pong(in <-chan string, out chan<- string) { + // recv message on ch1 + msg := <-in + msg = msg + " pong" + // send it on ch2 + out <- msg +} + +func main() { + // create ch1 and ch2 + ch1 := make(chan string) + ch2 := make(chan string) + + // spine goroutine ping and pong + go ping(ch1) + go pong(ch1, ch2) + + // recv message on ch2 + msg := <-ch2 + + fmt.Println(msg) +} diff --git a/01-intro/04-channel/05-channel/main.go b/01-intro-solution/02-channel/05-channel/main.go similarity index 59% rename from 01-intro/04-channel/05-channel/main.go rename to 01-intro-solution/02-channel/05-channel/main.go index b3517f2..074d984 100644 --- a/01-intro/04-channel/05-channel/main.go +++ b/01-intro-solution/02-channel/05-channel/main.go @@ -3,10 +3,21 @@ package main import "fmt" func main() { - //TODO: create channel owner goroutine which return channel and + // create channel owner goroutine which return channel and // writes data into channel and // closes the channel when done. + owner := func() chan int { + ch := make(chan int) + go func() { + defer close(ch) + for i := 0; i < 6; i++ { + ch <- i + } + }() + return ch + } + consumer := func(ch <-chan int) { // read values from channel for v := range ch { diff --git a/01-intro-solution/02-join/02-join/main.go b/01-intro-solution/02-join/02-join/main.go deleted file mode 100644 index 94e713b..0000000 --- a/01-intro-solution/02-join/02-join/main.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - "fmt" - "runtime" - "sync" -) - -// what will be output - -func main() { - runtime.GOMAXPROCS(1) - var wg sync.WaitGroup - - done := false - - wg.Add(1) - go func() { - defer wg.Done() - done = true - }() - wg.Wait() - for !done { - } - fmt.Println("finished") -} diff --git a/01-intro-solution/03-closure/03-closure/main.go b/01-intro-solution/03-closure/03-closure/main.go deleted file mode 100644 index 920f6b0..0000000 --- a/01-intro-solution/03-closure/03-closure/main.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - "sync" -) - -// What will be printed when the code below is executed? -// And fix the issue to assure that `len(m)` is printed as 10. - -func main() { - m := make(map[int]int) - - wg := &sync.WaitGroup{} - mu := &sync.Mutex{} - wg.Add(10) - for i := 0; i < 10; i++ { - go func() { - defer wg.Done() - mu.Lock() - m[i] = i - mu.Unlock() - }() - } - wg.Wait() - println(len(m)) -} diff --git a/01-intro/05-select/01-select/main.go b/01-intro-solution/03-select/01-select/main.go similarity index 56% rename from 01-intro/05-select/01-select/main.go rename to 01-intro-solution/03-select/01-select/main.go index 546e574..4314c2f 100644 --- a/01-intro/05-select/01-select/main.go +++ b/01-intro-solution/03-select/01-select/main.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "time" ) @@ -18,6 +19,14 @@ func main() { ch2 <- "two" }() - // TODO: multiplex recv on channel - ch1, ch2 + // multiplex recv on channel - ch1, ch2 + for i := 0; i < 2; i++ { + select { + case msg1 := <-ch1: + fmt.Println(msg1) + case msg2 := <-ch2: + fmt.Println(msg2) + } + } } diff --git a/01-intro-solution/03-select/02-select/main.go b/01-intro-solution/03-select/02-select/main.go new file mode 100644 index 0000000..f77155b --- /dev/null +++ b/01-intro-solution/03-select/02-select/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + ch := make(chan string, 1) + + go func() { + time.Sleep(2 * time.Second) + ch <- "one" + }() + + //implement timeout for recv on channel ch + select { + case m := <-ch: + fmt.Println(m) + case <-time.After(1 * time.Second): + fmt.Println("timeout") + } +} diff --git a/01-intro/05-select/03-select/main.go b/01-intro-solution/03-select/03-select/main.go similarity index 50% rename from 01-intro/05-select/03-select/main.go rename to 01-intro-solution/03-select/03-select/main.go index 528e83b..f3709b2 100644 --- a/01-intro/05-select/03-select/main.go +++ b/01-intro-solution/03-select/03-select/main.go @@ -13,9 +13,13 @@ func main() { ch <- "one" }() - // TODO: if there is no value on channel, do not block. + // if there is no value on channel, do not block. - m := <-ch - fmt.Println(m) + select { + case m := <-ch: + fmt.Println(m) + default: + fmt.Println("no message in channel") + } } diff --git a/01-intro/06-sync/01-mutex/main.go b/01-intro-solution/04-sync/01-mutex/main.go similarity index 76% rename from 01-intro/06-sync/01-mutex/main.go rename to 01-intro-solution/04-sync/01-mutex/main.go index efb1345..d1d82b1 100644 --- a/01-intro/06-sync/01-mutex/main.go +++ b/01-intro-solution/04-sync/01-mutex/main.go @@ -12,17 +12,22 @@ func main() { var balance int var wg sync.WaitGroup + var mu sync.Mutex deposit := func(amount int) { + mu.Lock() balance += amount + mu.Unlock() } withdrawal := func(amount int) { + mu.Lock() + defer mu.Unlock() balance -= amount } - // make 100 deposits of $1 - // and 100 withdrawal of $1 concurrently. + // we are making 100 times deposits of $1 + // and 100 times withdrawal of $1, concurrently. // run the program and check result. // TODO: fix the issue for consistent output. diff --git a/01-intro/06-sync/02-mutex/main.go b/01-intro-solution/04-sync/02-mutex/main.go similarity index 60% rename from 01-intro/06-sync/02-mutex/main.go rename to 01-intro-solution/04-sync/02-mutex/main.go index 64c35a7..5d317b1 100644 --- a/01-intro/06-sync/02-mutex/main.go +++ b/01-intro-solution/04-sync/02-mutex/main.go @@ -4,6 +4,7 @@ import ( "fmt" "runtime" "sync" + "time" ) func main() { @@ -12,7 +13,7 @@ func main() { var balance int var wg sync.WaitGroup - var mu sync.Mutex + var mu sync.RWMutex deposit := func(amount int) { mu.Lock() @@ -20,31 +21,30 @@ func main() { mu.Unlock() } - withdrawal := func(amount int) { - mu.Lock() - defer mu.Unlock() - balance -= amount + read := func() int { + mu.RLock() + defer mu.RUnlock() + return balance } - wg.Add(100) - for i := 0; i < 100; i++ { + wg.Add(10) + for i := 0; i < 10; i++ { + time.Sleep(1 * time.Millisecond) go func() { defer wg.Done() deposit(1) }() } - wg.Add(100) - for i := 0; i < 100; i++ { + // implement concurrent read. + // allow multiple reads, writes holds the lock exclusively. + wg.Add(10) + for i := 0; i < 10; i++ { go func() { defer wg.Done() - withdrawal(1) + fmt.Println(read()) }() } - - //TODO: implement concurrent read. - // allow multiple reads, writes holds the lock exclusively. - wg.Wait() fmt.Println(balance) } diff --git a/01-intro/06-sync/01-atomic/main.go b/01-intro-solution/04-sync/11-atomic/main.go similarity index 77% rename from 01-intro/06-sync/01-atomic/main.go rename to 01-intro-solution/04-sync/11-atomic/main.go index a4d0f36..4c34959 100644 --- a/01-intro/06-sync/01-atomic/main.go +++ b/01-intro-solution/04-sync/11-atomic/main.go @@ -4,6 +4,7 @@ import ( "fmt" "runtime" "sync" + "sync/atomic" ) func main() { @@ -12,14 +13,14 @@ func main() { var counter uint64 var wg sync.WaitGroup - // TODO: implement concurrency safe counter + // implement concurrency safe counter for i := 0; i < 50; i++ { wg.Add(1) go func() { defer wg.Done() for c := 0; c < 1000; c++ { - counter++ + atomic.AddUint64(&counter, 1) } }() } diff --git a/01-intro-solution/04-sync/21-cond/main.go b/01-intro-solution/04-sync/21-cond/main.go new file mode 100644 index 0000000..4b0bc4d --- /dev/null +++ b/01-intro-solution/04-sync/21-cond/main.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + "sync" +) + +var sharedRsc = make(map[string]interface{}) + +func main() { + var wg sync.WaitGroup + + m := sync.Mutex{} + c := sync.NewCond(&m) + + wg.Add(1) + go func() { + defer wg.Done() + + // suspend goroutine until sharedRsc is populated. + c.L.Lock() + for len(sharedRsc) == 0 { + c.Wait() + } + + fmt.Println(sharedRsc["rsc1"]) + c.L.Unlock() + }() + + // TODO: writes changes to sharedRsc + c.L.Lock() + sharedRsc["rsc1"] = "foo" + c.Signal() + c.L.Unlock() + wg.Wait() +} diff --git a/01-intro-solution/04-sync/22-cond/main.go b/01-intro-solution/04-sync/22-cond/main.go new file mode 100644 index 0000000..86c5093 --- /dev/null +++ b/01-intro-solution/04-sync/22-cond/main.go @@ -0,0 +1,53 @@ +package main + +import ( + "fmt" + "sync" +) + +var sharedRsc = make(map[string]interface{}) + +func main() { + var wg sync.WaitGroup + m := sync.Mutex{} + c := sync.NewCond(&m) + + wg.Add(1) + go func() { + defer wg.Done() + + // suspend goroutine until sharedRsc is populated. + + c.L.Lock() + for len(sharedRsc) == 0 { + c.Wait() + } + + fmt.Println(sharedRsc["rsc1"]) + c.L.Unlock() + }() + + wg.Add(1) + go func() { + defer wg.Done() + + // suspend goroutine until sharedRsc is populated. + + c.L.Lock() + for len(sharedRsc) == 0 { + c.Wait() + } + + fmt.Println(sharedRsc["rsc2"]) + c.L.Unlock() + }() + + // writes changes to sharedRsc + c.L.Lock() + sharedRsc["rsc1"] = "foo" + sharedRsc["rsc2"] = "bar" + c.Broadcast() + c.L.Unlock() + + wg.Wait() +} diff --git a/01-intro/06-sync/01-once/main.go b/01-intro-solution/04-sync/31-once/main.go similarity index 89% rename from 01-intro/06-sync/01-once/main.go rename to 01-intro-solution/04-sync/31-once/main.go index 9ed14c3..b9b5a96 100644 --- a/01-intro/06-sync/01-once/main.go +++ b/01-intro-solution/04-sync/31-once/main.go @@ -8,6 +8,8 @@ import ( func main() { var wg sync.WaitGroup + var once sync.Once + load := func() { fmt.Println("Run only once initialization function") } @@ -18,7 +20,7 @@ func main() { defer wg.Done() //TODO: modify so that load function gets called only once. - load() + once.Do(load) }() } wg.Wait() diff --git a/01-intro/06-sync/01-pool/main.go b/01-intro-solution/04-sync/41-pool/main.go similarity index 54% rename from 01-intro/06-sync/01-pool/main.go rename to 01-intro-solution/04-sync/41-pool/main.go index c02102c..47445ca 100644 --- a/01-intro/06-sync/01-pool/main.go +++ b/01-intro-solution/04-sync/41-pool/main.go @@ -2,15 +2,25 @@ package main import ( "bytes" + "fmt" "io" "os" + "sync" "time" ) -//TODO: create pool of bytes.Buffers which can be reused. +// create pool of bytes.Buffers which can be reused. + +var bufPool = sync.Pool{ + New: func() interface{} { + fmt.Println("allocate new bytes.Buffer") + return new(bytes.Buffer) + }, +} func log(w io.Writer, val string) { - var b bytes.Buffer + b := bufPool.Get().(*bytes.Buffer) + b.Reset() b.WriteString(time.Now().Format("15:04:05")) b.WriteString(" : ") @@ -18,6 +28,7 @@ func log(w io.Writer, val string) { b.WriteString("\n") w.Write(b.Bytes()) + bufPool.Put(b) } func main() { diff --git a/01-intro/07-race/main.go b/01-intro-solution/05-race/main.go similarity index 78% rename from 01-intro/07-race/main.go rename to 01-intro-solution/05-race/main.go index 6dbc79f..a645ed1 100644 --- a/01-intro/07-race/main.go +++ b/01-intro-solution/05-race/main.go @@ -11,12 +11,16 @@ import ( func main() { start := time.Now() + reset := make(chan bool) var t *time.Timer t = time.AfterFunc(randomDuration(), func() { fmt.Println(time.Now().Sub(start)) - t.Reset(randomDuration()) + reset <- true }) - time.Sleep(5 * time.Second) + for time.Since(start) < 5*time.Second { + <-reset + t.Reset(randomDuration()) + } } func randomDuration() time.Duration { diff --git a/01-intro-solution/08-exercise/05-exercise/absdata/absdata.go b/01-intro-solution/06-exercise/05-exercise/absdata/absdata.go similarity index 100% rename from 01-intro-solution/08-exercise/05-exercise/absdata/absdata.go rename to 01-intro-solution/06-exercise/05-exercise/absdata/absdata.go diff --git a/01-intro-solution/09-exercise-web-crawler-solution/main.go b/01-intro-solution/07-exercise-web-crawler-solution/main.go similarity index 100% rename from 01-intro-solution/09-exercise-web-crawler-solution/main.go rename to 01-intro-solution/07-exercise-web-crawler-solution/main.go diff --git a/01-intro-solution/09-exercise-web-crawler/main.go b/01-intro-solution/07-exercise-web-crawler/main.go similarity index 100% rename from 01-intro-solution/09-exercise-web-crawler/main.go rename to 01-intro-solution/07-exercise-web-crawler/main.go diff --git a/01-intro-solution/07-race/main.go b/01-intro-solution/07-race/main.go deleted file mode 100644 index 6dbc79f..0000000 --- a/01-intro-solution/07-race/main.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "fmt" - "math/rand" - "time" -) - -//TODO: identify the data race -// fix the issue. - -func main() { - start := time.Now() - var t *time.Timer - t = time.AfterFunc(randomDuration(), func() { - fmt.Println(time.Now().Sub(start)) - t.Reset(randomDuration()) - }) - time.Sleep(5 * time.Second) -} - -func randomDuration() time.Duration { - return time.Duration(rand.Int63n(1e9)) -} diff --git a/01-intro/02-join/01-join/main.go b/01-intro/01-goroutines/03-join/main.go similarity index 100% rename from 01-intro/02-join/01-join/main.go rename to 01-intro/01-goroutines/03-join/main.go diff --git a/01-intro/01-goroutines/04-add/counting/count.go b/01-intro/01-goroutines/04-add/counting/count.go new file mode 100644 index 0000000..cee6add --- /dev/null +++ b/01-intro/01-goroutines/04-add/counting/count.go @@ -0,0 +1,45 @@ +package counting + +import ( + "math/rand" + "time" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// GenerateNumbers - random number generation +func GenerateNumbers(max int) []int { + rand.Seed(time.Now().UnixNano()) + numbers := make([]int, max) + for i := 0; i < max; i++ { + numbers[i] = rand.Intn(10) + } + return numbers +} + +// Add - sequential code to add numbers +func Add(numbers []int) int64 { + var sum int64 + for _, n := range numbers { + sum += int64(n) + } + return sum +} + +//TODO: complete the concurrent version of add function. + +// AddConcurrent - concurrent code to add numbers +func AddConcurrent(numbers []int) int64 { + var sum int64 + // Utilize all cores on machine + + // Divide the input into parts + + // Run computation for each part in seperate goroutine. + + // Add part sum to cummulative sum + + return sum +} diff --git a/01-intro/01-goroutines/04-add/counting/count_test.go b/01-intro/01-goroutines/04-add/counting/count_test.go new file mode 100644 index 0000000..e46f31b --- /dev/null +++ b/01-intro/01-goroutines/04-add/counting/count_test.go @@ -0,0 +1,19 @@ +package counting + +import ( + "testing" +) + +func BenchmarkAdd(b *testing.B) { + numbers := GenerateNumbers(1e7) + for i := 0; i < b.N; i++ { + Add(numbers) + } +} + +func BenchmarkAddConcurrent(b *testing.B) { + numbers := GenerateNumbers(1e7) + for i := 0; i < b.N; i++ { + AddConcurrent(numbers) + } +} diff --git a/01-intro/01-goroutines/04-add/main.go b/01-intro/01-goroutines/04-add/main.go new file mode 100644 index 0000000..70874d5 --- /dev/null +++ b/01-intro/01-goroutines/04-add/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "fmt" + "time" + + "github.com/andcloudio/go-concurrency-exercises/01-intro/01-goroutines/04-add/counting" +) + +func main() { + numbers := counting.GenerateNumbers(1e7) + + t := time.Now() + _ = counting.Add(numbers) + fmt.Printf("Sequential Add took: %s\n", time.Since(t)) + + t = time.Now() + _ = counting.AddConcurrent(numbers) + fmt.Printf("Concurrent Add took: %s\n", time.Since(t)) +} diff --git a/01-intro/03-closure/01-closure/main.go b/01-intro/01-goroutines/05-closure/main.go similarity index 83% rename from 01-intro/03-closure/01-closure/main.go rename to 01-intro/01-goroutines/05-closure/main.go index 5cb151f..a1ee089 100644 --- a/01-intro/03-closure/01-closure/main.go +++ b/01-intro/01-goroutines/05-closure/main.go @@ -18,8 +18,9 @@ func main() { go func() { defer wg.Done() i++ - fmt.Println(i) + fmt.Printf("value of i: %v\n", i) }() + fmt.Println("return from function") return } diff --git a/01-intro/03-closure/02-closure/main.go b/01-intro/01-goroutines/06-closure/main.go similarity index 88% rename from 01-intro/03-closure/02-closure/main.go rename to 01-intro/01-goroutines/06-closure/main.go index 5225945..2524ae2 100644 --- a/01-intro/03-closure/02-closure/main.go +++ b/01-intro/01-goroutines/06-closure/main.go @@ -11,7 +11,7 @@ func main() { // what is the output //TODO: fix the issue. - for i := 0; i < 3; i++ { + for i := 1; i <= 3; i++ { wg.Add(1) go func() { defer wg.Done() diff --git a/01-intro-solution/04-channel/01-channel/main.go b/01-intro/02-channel/01-channel/main.go similarity index 100% rename from 01-intro-solution/04-channel/01-channel/main.go rename to 01-intro/02-channel/01-channel/main.go diff --git a/01-intro-solution/04-channel/02-channel/main.go b/01-intro/02-channel/02-channel/main.go similarity index 100% rename from 01-intro-solution/04-channel/02-channel/main.go rename to 01-intro/02-channel/02-channel/main.go diff --git a/01-intro-solution/04-channel/03-channel/main.go b/01-intro/02-channel/03-channel/main.go similarity index 100% rename from 01-intro-solution/04-channel/03-channel/main.go rename to 01-intro/02-channel/03-channel/main.go diff --git a/01-intro-solution/04-channel/04-channel/main.go b/01-intro/02-channel/04-channel/main.go similarity index 100% rename from 01-intro-solution/04-channel/04-channel/main.go rename to 01-intro/02-channel/04-channel/main.go diff --git a/01-intro-solution/04-channel/05-channel/main.go b/01-intro/02-channel/05-channel/main.go similarity index 100% rename from 01-intro-solution/04-channel/05-channel/main.go rename to 01-intro/02-channel/05-channel/main.go diff --git a/01-intro/02-join/02-join/main.go b/01-intro/02-join/02-join/main.go deleted file mode 100644 index 4e91eb0..0000000 --- a/01-intro/02-join/02-join/main.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "fmt" - "runtime" -) - -// what will be the output - -func main() { - runtime.GOMAXPROCS(1) - - done := false - - go func() { - done = true - }() - - for !done { - } - fmt.Println("finished") -} diff --git a/01-intro/02-join/03-add/main.go b/01-intro/02-join/03-add/main.go deleted file mode 100644 index c68fa4e..0000000 --- a/01-intro/02-join/03-add/main.go +++ /dev/null @@ -1,32 +0,0 @@ -package main - -import ( - "fmt" - "math/rand" - "time" - - "github.com/dgunjetti/sequential/counting" -) - -func generateNumbers(max int) []int { - rand.Seed(time.Now().UnixNano()) - numbers := make([]int, max) - for i := 0; i < max; i++ { - numbers[i] = rand.Intn(10) - } - return numbers -} - -func main() { - - numbers := generateNumbers(1e7) - - t := time.Now() - _ = counting.Add(numbers) - fmt.Printf("Sequential Add took: %s\n", time.Since(t)) - - t = time.Now() - _ = counting.AddConcurrent(numbers) - fmt.Printf("Concurrent Add took: %s\n", time.Since(t)) - -} diff --git a/01-intro/03-closure/03-closure/main.go b/01-intro/03-closure/03-closure/main.go deleted file mode 100644 index 920f6b0..0000000 --- a/01-intro/03-closure/03-closure/main.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - "sync" -) - -// What will be printed when the code below is executed? -// And fix the issue to assure that `len(m)` is printed as 10. - -func main() { - m := make(map[int]int) - - wg := &sync.WaitGroup{} - mu := &sync.Mutex{} - wg.Add(10) - for i := 0; i < 10; i++ { - go func() { - defer wg.Done() - mu.Lock() - m[i] = i - mu.Unlock() - }() - } - wg.Wait() - println(len(m)) -} diff --git a/01-intro-solution/05-select/01-select/main.go b/01-intro/03-select/01-select/main.go similarity index 100% rename from 01-intro-solution/05-select/01-select/main.go rename to 01-intro/03-select/01-select/main.go diff --git a/01-intro-solution/05-select/02-select/main.go b/01-intro/03-select/02-select/main.go similarity index 100% rename from 01-intro-solution/05-select/02-select/main.go rename to 01-intro/03-select/02-select/main.go diff --git a/01-intro-solution/05-select/03-select/main.go b/01-intro/03-select/03-select/main.go similarity index 100% rename from 01-intro-solution/05-select/03-select/main.go rename to 01-intro/03-select/03-select/main.go diff --git a/01-intro/04-channel/01-channel/main.go b/01-intro/04-channel/01-channel/main.go deleted file mode 100644 index ccd1af1..0000000 --- a/01-intro/04-channel/01-channel/main.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -func main() { - go func(a, b int) { - c := a + b - }(1, 2) - // TODO: get the value computed from goroutine - // fmt.Printf("computed value %v\n", c) -} diff --git a/01-intro/04-channel/02-channel/main.go b/01-intro/04-channel/02-channel/main.go deleted file mode 100644 index d4d1a06..0000000 --- a/01-intro/04-channel/02-channel/main.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -func main() { - go func() { - for i := 0; i < 6; i++ { - // TODO: send iterator over channel - } - }() - - // TODO: range over channel to recv values - -} diff --git a/01-intro/04-channel/04-channel/main.go b/01-intro/04-channel/04-channel/main.go deleted file mode 100644 index 4406cb2..0000000 --- a/01-intro/04-channel/04-channel/main.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -// TODO: Implement ping pong with Channel Direction - -func ping() { - // send message on ch1 -} - -func pong() { - // recv message on ch1 - // send it on ch2 -} - -func main() { - // create ch1 and ch2 - - // spine goroutine ping and pong - - // recv message on ch2 -} diff --git a/01-intro-solution/06-sync/01-mutex/main.go b/01-intro/04-sync/01-mutex/main.go similarity index 100% rename from 01-intro-solution/06-sync/01-mutex/main.go rename to 01-intro/04-sync/01-mutex/main.go diff --git a/01-intro-solution/06-sync/02-mutex/main.go b/01-intro/04-sync/02-mutex/main.go similarity index 64% rename from 01-intro-solution/06-sync/02-mutex/main.go rename to 01-intro/04-sync/02-mutex/main.go index 64c35a7..7727571 100644 --- a/01-intro-solution/06-sync/02-mutex/main.go +++ b/01-intro/04-sync/02-mutex/main.go @@ -20,28 +20,14 @@ func main() { mu.Unlock() } - withdrawal := func(amount int) { - mu.Lock() - defer mu.Unlock() - balance -= amount - } - - wg.Add(100) - for i := 0; i < 100; i++ { + wg.Add(10) + for i := 0; i < 10; i++ { go func() { defer wg.Done() deposit(1) }() } - wg.Add(100) - for i := 0; i < 100; i++ { - go func() { - defer wg.Done() - withdrawal(1) - }() - } - //TODO: implement concurrent read. // allow multiple reads, writes holds the lock exclusively. diff --git a/01-intro-solution/06-sync/01-atomic/main.go b/01-intro/04-sync/11-atomic/main.go similarity index 100% rename from 01-intro-solution/06-sync/01-atomic/main.go rename to 01-intro/04-sync/11-atomic/main.go diff --git a/01-intro-solution/06-sync/01-cond/main.go b/01-intro/04-sync/21-cond/main.go similarity index 100% rename from 01-intro-solution/06-sync/01-cond/main.go rename to 01-intro/04-sync/21-cond/main.go diff --git a/01-intro/06-sync/01-cond/main.go b/01-intro/04-sync/22-cond/main.go similarity index 63% rename from 01-intro/06-sync/01-cond/main.go rename to 01-intro/04-sync/22-cond/main.go index 4ac269a..d97d977 100644 --- a/01-intro/06-sync/01-cond/main.go +++ b/01-intro/04-sync/22-cond/main.go @@ -24,8 +24,22 @@ func main() { fmt.Println(sharedRsc["rsc1"]) }() + wg.Add(1) + go func() { + defer wg.Done() + + //TODO: suspend goroutine until sharedRsc is populated. + + for len(sharedRsc) == 0 { + time.Sleep(1 * time.Millisecond) + } + + fmt.Println(sharedRsc["rsc2"]) + }() + // writes changes to sharedRsc sharedRsc["rsc1"] = "foo" + sharedRsc["rsc2"] = "bar" wg.Wait() } diff --git a/01-intro-solution/06-sync/01-once/main.go b/01-intro/04-sync/31-once/main.go similarity index 100% rename from 01-intro-solution/06-sync/01-once/main.go rename to 01-intro/04-sync/31-once/main.go diff --git a/01-intro-solution/06-sync/01-pool/main.go b/01-intro/04-sync/41-pool/main.go similarity index 100% rename from 01-intro-solution/06-sync/01-pool/main.go rename to 01-intro/04-sync/41-pool/main.go diff --git a/01-intro/05-race/main.go b/01-intro/05-race/main.go new file mode 100644 index 0000000..f994c71 --- /dev/null +++ b/01-intro/05-race/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "fmt" + "math/rand" + "time" +) + +//TODO: identify the data race +// fix the issue. + +func main() { + start := time.Now() + var t *time.Timer + t = time.AfterFunc(randomDuration(), func() { + fmt.Println(time.Now().Sub(start)) + t.Reset(randomDuration()) + }) + time.Sleep(5 * time.Second) +} + +func randomDuration() time.Duration { + return time.Duration(rand.Int63n(1e9)) +} + +//---------------------------------------------------- +// (main goroutine) -> t <- (time.AfterFunc goroutine) +//---------------------------------------------------- +// (working condition) +// main goroutine.. +// t = time.AfterFunc() // returns a timer.. + +// AfterFunc goroutine +// t.Reset() // timer reset +//---------------------------------------------------- +// (race condition- random duration is very small) +// AfterFunc goroutine +// t.Reset() // t = nil + +// main goroutine.. +// t = time.AfterFunc() +//---------------------------------------------------- diff --git a/01-intro/05-select/02-select/main.go b/01-intro/05-select/02-select/main.go deleted file mode 100644 index 8933bb5..0000000 --- a/01-intro/05-select/02-select/main.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -func main() { - ch := make(chan string, 1) - - go func() { - time.Sleep(2 * time.Second) - ch <- "one" - }() - - // TODO: implement timeout for recv on channel ch - - m := <-ch - fmt.Println(m) -} diff --git a/01-intro-solution/08-exercise/01-exercise/main.go b/01-intro/06-exercise/01-exercise/main.go similarity index 100% rename from 01-intro-solution/08-exercise/01-exercise/main.go rename to 01-intro/06-exercise/01-exercise/main.go diff --git a/01-intro-solution/08-exercise/02-exercise/main.go b/01-intro/06-exercise/02-exercise/main.go similarity index 100% rename from 01-intro-solution/08-exercise/02-exercise/main.go rename to 01-intro/06-exercise/02-exercise/main.go diff --git a/01-intro-solution/08-exercise/03-exercise/main.go b/01-intro/06-exercise/03-exercise/main.go similarity index 100% rename from 01-intro-solution/08-exercise/03-exercise/main.go rename to 01-intro/06-exercise/03-exercise/main.go diff --git a/01-intro-solution/08-exercise/04-exercise/main.go b/01-intro/06-exercise/04-exercise/main.go similarity index 100% rename from 01-intro-solution/08-exercise/04-exercise/main.go rename to 01-intro/06-exercise/04-exercise/main.go diff --git a/01-intro/08-exercise/05-exercise/absdata/absdata.go b/01-intro/06-exercise/05-exercise/absdata/absdata.go similarity index 100% rename from 01-intro/08-exercise/05-exercise/absdata/absdata.go rename to 01-intro/06-exercise/05-exercise/absdata/absdata.go diff --git a/01-intro/09-exercise-web-crawler-solution/main.go b/01-intro/07-exercise-web-crawler-solution/main.go similarity index 100% rename from 01-intro/09-exercise-web-crawler-solution/main.go rename to 01-intro/07-exercise-web-crawler-solution/main.go diff --git a/01-intro/09-exercise-web-crawler/main.go b/01-intro/07-exercise-web-crawler/main.go similarity index 100% rename from 01-intro/09-exercise-web-crawler/main.go rename to 01-intro/07-exercise-web-crawler/main.go diff --git a/01-intro/08-exercise/01-exercise/main.go b/01-intro/08-exercise/01-exercise/main.go deleted file mode 100644 index 0f035c0..0000000 --- a/01-intro/08-exercise/01-exercise/main.go +++ /dev/null @@ -1,33 +0,0 @@ -package main - -import ( - "fmt" - "runtime" - "sync" -) - -// What will be printed when the code below is executed? -// Will it be different when line A is changed to `GOMAXPROCS=2` ? - -func main() { - const GOMAXPROCS = 1 //A - runtime.GOMAXPROCS(GOMAXPROCS) - - var wg sync.WaitGroup - wg.Add(2) - - go func() { - defer wg.Done() - for char := 0; char < 26; char++ { - fmt.Printf("%c ", 'A'+char) - } - }() - go func() { - defer wg.Done() - for char := 0; char < 26; char++ { - fmt.Printf("%c ", 'a'+char) - } - }() - - wg.Wait() -} \ No newline at end of file diff --git a/01-intro/08-exercise/02-exercise/main.go b/01-intro/08-exercise/02-exercise/main.go deleted file mode 100644 index 9c1b12c..0000000 --- a/01-intro/08-exercise/02-exercise/main.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - "math/rand" - "sync" -) - -const N = 10 - -//TODO: Fix the issue below to avoid "concurrent map writes" error. - -func main() { - m := make(map[int]int) - - wg := &sync.WaitGroup{} - - wg.Add(N) - for i := 0; i < N; i++ { - go func() { - defer wg.Done() - m[rand.Int()] = rand.Int() - }() - } - wg.Wait() - println(len(m)) -} diff --git a/01-intro/08-exercise/03-exercise/main.go b/01-intro/08-exercise/03-exercise/main.go deleted file mode 100644 index d5b0e67..0000000 --- a/01-intro/08-exercise/03-exercise/main.go +++ /dev/null @@ -1,32 +0,0 @@ -package main - -import ( - "fmt" - "runtime" - "sync" -) - -const N = 26 - -//TODO: Add code in line A to assure that the lowercase letters and -// capital letters are printed consecutively. - -func main() { - const GOMAXPROCS = 1 - runtime.GOMAXPROCS(GOMAXPROCS) - - var wg sync.WaitGroup - wg.Add(2 * N) - for i := 0; i < N; i++ { - go func(i int) { - defer wg.Done() - // A - fmt.Printf("%c", 'a'+i) - }(i) - go func(i int) { - defer wg.Done() - fmt.Printf("%c", 'A'+i) - }(i) - } - wg.Wait() -} diff --git a/01-intro/08-exercise/04-exercise/main.go b/01-intro/08-exercise/04-exercise/main.go deleted file mode 100644 index 8b49e7c..0000000 --- a/01-intro/08-exercise/04-exercise/main.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -const NumberOfReaders = 10 -const NumberOfWriters = 10 - -//TODO: complete the program to make writer and readers -// concurrency safe. - -func writer() { - // Write to data. -} - -func reader() { - // Read from data. -} - -func main() { - for i := 0; i < NumberOfReaders; i++ { - go reader() - } - for i := 0; i < NumberOfWriters; i++ { - go writer() - } -}