-
-
Notifications
You must be signed in to change notification settings - Fork 654
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
551 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"blurb": "Channels are the pipes that connect concurrent goroutines.", | ||
"authors": ["RezaSi"], | ||
"contributors": ["RezaSi"] | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# About | ||
|
||
Channels are a typed conduit through which you can send and receive values with the channel operator, <-. (The data flows in the direction of the arrow.) | ||
|
||
```go | ||
ch <- v // Send v to channel ch. | ||
v := <-ch // Receive from ch, and assign value to v. | ||
``` | ||
|
||
Create a new channel with make(chan val-type). Channels are typed by the values they convey. | ||
|
||
```go | ||
ch := make(chan int) | ||
``` | ||
|
||
By default, sends and receives block wait until the other side is ready. This allows goroutines to synchronize without explicit locks or condition variables. | ||
|
||
|
||
Example | ||
```go | ||
package main | ||
|
||
import "fmt" | ||
|
||
func exist(slice []int, x int, c chan bool) { | ||
found := false | ||
for _, v := range slice { | ||
if v == x { | ||
found = true | ||
} | ||
} | ||
c <- found // send found to c | ||
} | ||
|
||
func main() { | ||
slice := []int{7, 2, 8, -9, 4, 0} | ||
findValue := 8 | ||
|
||
c := make(chan bool) | ||
go exist(slice[:len(slice)/2], findValue, c) | ||
go exist(slice[len(slice)/2:], findValue, c) | ||
x, y := <-c, <-c // receive from c | ||
|
||
fmt.Println(x || y) | ||
} | ||
``` | ||
|
||
## Buffered Channels | ||
|
||
Channels can be buffered. Provide the buffer length as the second argument to make to initialize a buffered channel: | ||
|
||
```go | ||
ch := make(chan int, 100) | ||
``` | ||
|
||
Sends to a buffered channel block only when the buffer is full. Receives block when the buffer is empty. | ||
|
||
|
||
## Range and Close | ||
|
||
A sender can close a channel to indicate that no more values will be sent. Receivers can test whether a channel has been closed by assigning a second parameter to the receive expression: after | ||
|
||
```go | ||
v, ok := <-ch | ||
``` | ||
|
||
`ok` is `false` if there are no more values to receive and the channel is closed. | ||
|
||
The loop `for i := range c` receives values from the channel repeatedly until it is closed. | ||
|
||
### Notes: | ||
- Only the sender should close a channel, never the receiver. Sending on a closed channel will cause a panic. | ||
|
||
- Channels aren't like files; you don't usually need to close them. Closing is only necessary when the receiver must be told there are no more values coming, such as to terminate a range loop. | ||
|
||
## Select | ||
|
||
The `select` statement lets a goroutine wait on multiple communication operations. | ||
|
||
A `select` blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready. | ||
|
||
Example | ||
```go | ||
package main | ||
|
||
import "fmt" | ||
|
||
func fibonacci(c, quit chan int) { | ||
x, y := 0, 1 | ||
for { | ||
select { | ||
case c <- x: | ||
x, y = y, x+y | ||
case <-quit: | ||
fmt.Println("quit") | ||
return | ||
} | ||
} | ||
} | ||
|
||
func main() { | ||
c := make(chan int) | ||
quit := make(chan int) | ||
go func() { | ||
for i := 0; i < 10; i++ { | ||
fmt.Println(<-c) | ||
} | ||
quit <- 0 | ||
}() | ||
fibonacci(c, quit) | ||
} | ||
|
||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Introduction | ||
|
||
Channels are a typed conduit through which you can send and receive values with the channel operator, <-. (The data flows in the direction of the arrow.) | ||
|
||
```go | ||
ch <- v // Send v to channel ch. | ||
v := <-ch // Receive from ch, and assign value to v. | ||
``` | ||
|
||
Create a new channel with make(chan val-type). Channels are typed by the values they convey. | ||
|
||
```go | ||
ch := make(chan int) | ||
``` | ||
|
||
By default, sends and receives block wait until the other side is ready. This allows goroutines to synchronize without explicit locks or condition variables. | ||
|
||
|
||
Example | ||
```go | ||
package main | ||
|
||
import "fmt" | ||
|
||
func exist(slice []int, x int, c chan bool) { | ||
found := false | ||
for _, v := range slice { | ||
if v == x { | ||
found = true | ||
} | ||
} | ||
c <- found // send found to c | ||
} | ||
|
||
func main() { | ||
slice := []int{7, 2, 8, -9, 4, 0} | ||
findValue := 8 | ||
|
||
c := make(chan bool) | ||
go exist(slice[:len(slice)/2], findValue, c) | ||
go exist(slice[len(slice)/2:], findValue, c) | ||
x, y := <-c, <-c // receive from c | ||
|
||
fmt.Println(x || y) | ||
} | ||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
[ | ||
{ | ||
"url": "https://go.dev/tour/concurrency/2", | ||
"description": "Tour of Go: Channels" | ||
}, | ||
{ | ||
"url": "https://go.dev/tour/concurrency/3", | ||
"description": "Tour of Go: Buffered Channels" | ||
}, | ||
{ | ||
"url": "https://go.dev/tour/concurrency/4", | ||
"description": "Tour of Go: Range and Close" | ||
}, | ||
{ | ||
"url": "https://go.dev/tour/concurrency/5", | ||
"description": "Tour of Go: Select" | ||
}, | ||
{ | ||
"url": "https://gobyexample.com/channels", | ||
"description": "Go by Example: Channels" | ||
} | ||
] |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Hints | ||
|
||
## General | ||
|
||
- To learn more about types in Go, check [Tour of Go: Basic Types][basic types]. | ||
- To learn more about type conversions in Go, check [Tour of Go: Type Conversions][type conversions]. | ||
|
||
## 1. Calculate the number of working cars produced per hour | ||
|
||
- The percentage (passed as an argument) is a number between 0-100. To make this percentage a bit easier to work with, start by dividing it by 100. | ||
- To compute the number of cars produced successfully, multiply the percentage (divided by 100) by the number of cars produced. | ||
- When multiplying two numbers together, they both need to be of the same type. Use [type conversions][type conversions] if needed. | ||
|
||
## 2. Calculate the number of working cars produced per minute | ||
|
||
- Start by calculating the production of successful cars per hour. For this, you can use the `CalculateProductionRatePerHour` function you made from the previous step. | ||
- Knowing the production per hour of cars, you can get the production per minute by dividing the production per hour by 60 (the number of minutes in an hour). | ||
- Remember to cast the result to an `int`. | ||
|
||
## 3. Calculate the cost of production | ||
|
||
- Start by working out how many groups of 10 cars there are. You can do this by dividing the number of cars by 10. | ||
- Then work out how many cars are remaining (the [modulo operator][modulo operator] is useful for this). | ||
- To arrive at the cost, multiply the number of groups by the cost to produce 10 cars and then multiply the number of cars remaining by the cost to produce each individual car. Then sum the results of the multiplication together. | ||
|
||
[basic types]: https://tour.golang.org/basics/11 | ||
[type conversions]: https://tour.golang.org/basics/13 | ||
[modulo operator]: https://golangbyexample.com/remainder-modulus-go-golang/ |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Instructions | ||
|
||
In this exercise you'll be writing code to handle multilayer cache with golang channels. | ||
|
||
## 1. Get value from fastest layer | ||
|
||
We have multiple layers of cache, and we want to get the value from the fastest layer. the layers of cache given to you as `cacheLayers` parameter. | ||
|
||
any cache struct in the cacheLayer is like this: | ||
|
||
```go | ||
type Cache struct { | ||
ResponseTime time.Duration | ||
Data map[string]string | ||
} | ||
``` | ||
|
||
as you see, the `ResponseTime` is the time it takes to get(or set) the value from(to) the cache, and the `Data` is the data stored in the cache. | ||
|
||
you have to get a value from the layer have the value for this key as fast as possible and return it with `nil` error or return `ErrKeyNotExist` error if the key does not exist in any layer. | ||
|
||
|
||
```go | ||
GetValueFromFastestLayer(cacheLayers []Cache, key string) (string, error) | ||
``` | ||
|
||
## 2. Set value to all layers | ||
The key and value are given to you as `key` and `value` parameter. | ||
|
||
you have to set the value to all `cacheLayers` as fast as possible. | ||
|
||
```go | ||
SetValueToAllLayers(cacheLayers []Cache, key string, value string) error | ||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Introduction | ||
|
||
Channels are a typed conduit through which you can send and receive values with the channel operator, <-. (The data flows in the direction of the arrow.) | ||
|
||
```go | ||
ch <- v // Send v to channel ch. | ||
v := <-ch // Receive from ch, and assign value to v. | ||
``` | ||
|
||
Create a new channel with make(chan val-type). Channels are typed by the values they convey. | ||
|
||
```go | ||
ch := make(chan int) | ||
``` | ||
|
||
By default, sends and receives block wait until the other side is ready. This allows goroutines to synchronize without explicit locks or condition variables. | ||
|
||
|
||
Example | ||
```go | ||
package main | ||
|
||
import "fmt" | ||
|
||
func exist(slice []int, x int, c chan bool) { | ||
found := false | ||
for _, v := range slice { | ||
if v == x { | ||
found = true | ||
} | ||
} | ||
c <- found // send found to c | ||
} | ||
|
||
func main() { | ||
slice := []int{7, 2, 8, -9, 4, 0} | ||
findValue := 8 | ||
|
||
c := make(chan bool) | ||
go exist(slice[:len(slice)/2], findValue, c) | ||
go exist(slice[len(slice)/2:], findValue, c) | ||
x, y := <-c, <-c // receive from c | ||
|
||
fmt.Println(x || y) | ||
} | ||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"blurb": "Learn about numbers and type conversion by analyzing an assembly line in a car factory.", | ||
"authors": ["RezaSi"], | ||
"contributors": [], | ||
"files": { | ||
"solution": [ | ||
"channel.go" | ||
], | ||
"test": [ | ||
"channel_test.go" | ||
], | ||
"exemplar": [ | ||
".meta/exemplar.go" | ||
] | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Design | ||
|
||
## Goal | ||
|
||
The goal of this exercise is to teach the student how to deal with channels and select in Go. | ||
|
||
## Learning objectives | ||
|
||
- understand what channels are | ||
- the difference between buffered and unbuffered channels | ||
- closing channels | ||
- for loop over a channel: for x := range ch { ... } | ||
- use select to receive from several channels | ||
|
||
## Concepts | ||
|
||
- `channels` | ||
|
||
## Prerequisites | ||
|
||
- `functions` | ||
- `for-loops` | ||
- `range-iteration` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package channels | ||
|
||
func GetValueFromFastestLayer(cacheLayers []Cache, key string) (string, error) { | ||
ch := make(chan string, len(cacheLayers)) | ||
for _, cache := range cacheLayers { | ||
go func(cache Cache) { | ||
value, _ := cache.Get(key) | ||
ch <- value | ||
}(cache) | ||
} | ||
|
||
for range cacheLayers { | ||
value := <-ch | ||
if value != "" { | ||
return value, nil | ||
} | ||
} | ||
|
||
return "", ErrKeyNotExist | ||
} | ||
|
||
func SetValueToAllLayers(cacheLayers []Cache, key string, value string) error { | ||
ch := make(chan error, len(cacheLayers)) | ||
for _, cache := range cacheLayers { | ||
go func(cache Cache) { | ||
err := cache.Set(key, value) | ||
ch <- err | ||
}(cache) | ||
} | ||
|
||
for range cacheLayers { | ||
<-ch | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.