Compare commits
2 Commits
f16bfef103
...
c7083f9028
Author | SHA1 | Date | |
---|---|---|---|
c7083f9028 | |||
f0c2621469 |
28
1-echo-text/main.go
Normal file
28
1-echo-text/main.go
Normal file
@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
@Ref: https://livebook.manning.com/book/go-in-practice/chapter-3/65
|
||||
`os.Stdin` and `os.Stdout` will be used as the system input and output. It's great.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
func main() {
|
||||
go echo(os.Stdin, os.Stdout)
|
||||
|
||||
time.Sleep(30 * time.Second)
|
||||
|
||||
fmt.Println("Time out.")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func echo(in io.Reader, out io.Writer) {
|
||||
io.Copy(out, in)
|
||||
}
|
68
2-compress-file/main.go
Normal file
68
2-compress-file/main.go
Normal file
@ -0,0 +1,68 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
/*
|
||||
@Ref: https://livebook.manning.com/book/go-in-practice/chapter-3/65
|
||||
1. Practice gzip compress
|
||||
2. How to use wait group
|
||||
3. os.Args[1:] can stream in multiple files to the program without writing a walk function. Command: go run main.go ./testdata/*
|
||||
4. Passing the filename to each goroutine can make sure the correct file is executed as it's scheduled
|
||||
|
||||
*/
|
||||
func main() {
|
||||
|
||||
// Single thread
|
||||
// for _, file := range os.Args[1:] {
|
||||
|
||||
// err := compress(file)
|
||||
// if err != nil {
|
||||
// os.Exit(0)
|
||||
// }
|
||||
// }
|
||||
|
||||
// Multi threads
|
||||
wg := sync.WaitGroup{}
|
||||
var (
|
||||
i int
|
||||
file string
|
||||
)
|
||||
for i, file = range os.Args[1:] {
|
||||
wg.Add(1)
|
||||
go func(filename string) {
|
||||
compress(filename)
|
||||
wg.Done()
|
||||
}(file)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
fmt.Printf("Compressed %d files\n", i+1)
|
||||
}
|
||||
|
||||
func compress(filename string) error {
|
||||
in, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer in.Close()
|
||||
|
||||
out, err := os.Create(filename + ".gz")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer out.Close()
|
||||
|
||||
gzout := gzip.NewWriter(out)
|
||||
_, err = io.Copy(gzout, in)
|
||||
gzout.Close()
|
||||
|
||||
return err
|
||||
}
|
79
3-word-counter/main.go
Normal file
79
3-word-counter/main.go
Normal file
@ -0,0 +1,79 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
@Ref: https://livebook.manning.com/book/go-in-practice/chapter-3/65
|
||||
1. --reac flag is able to do the race detection
|
||||
2. How to use scanner to split the word in a file
|
||||
3. sync.Mutex usage
|
||||
*/
|
||||
|
||||
func main() {
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
w := newWords()
|
||||
for _, file := range os.Args[1:] {
|
||||
wg.Add(1)
|
||||
go func(filename string) {
|
||||
tallyWords(filename, w)
|
||||
wg.Done()
|
||||
}(file)
|
||||
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
fmt.Println("Words that appear more than once:")
|
||||
for word, count := range w.found {
|
||||
if count > 1 {
|
||||
fmt.Printf("%s: %d\n", word, count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type words struct {
|
||||
sync.Mutex
|
||||
found map[string]int
|
||||
}
|
||||
|
||||
func newWords() *words {
|
||||
return &words{found: make(map[string]int)}
|
||||
}
|
||||
|
||||
func (w *words) add(word string, n int) {
|
||||
w.Lock()
|
||||
defer w.Unlock()
|
||||
|
||||
count, ok := w.found[word]
|
||||
if !ok {
|
||||
w.found[word] = n
|
||||
return
|
||||
}
|
||||
w.found[word] = count + n
|
||||
}
|
||||
|
||||
func tallyWords(filename string, dist *words) error {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
scanner.Split(bufio.ScanWords)
|
||||
for scanner.Scan() {
|
||||
word := strings.ToLower(scanner.Text())
|
||||
dist.add(word, 1)
|
||||
}
|
||||
return scanner.Err()
|
||||
}
|
40
4-multi-channels/main.go
Normal file
40
4-multi-channels/main.go
Normal file
@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
@Ref: https://livebook.manning.com/book/go-in-practice/chapter-3/65
|
||||
1. time.After returns a channel
|
||||
2. channel usage
|
||||
3. select usage
|
||||
4. channel declaration with specifying a direction
|
||||
*/
|
||||
|
||||
func main() {
|
||||
done := time.After(30 * time.Second)
|
||||
echo := make(chan []byte)
|
||||
go readStdin(echo)
|
||||
for {
|
||||
select {
|
||||
case buf := <-echo:
|
||||
os.Stdout.Write(buf)
|
||||
case <-done:
|
||||
fmt.Println("Time out")
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readStdin(out chan<- []byte) {
|
||||
for {
|
||||
data := make([]byte, 1024)
|
||||
l, _ := os.Stdin.Read(data)
|
||||
if l > 0 {
|
||||
out <- data
|
||||
}
|
||||
}
|
||||
}
|
70
5-close-channels/main.go
Normal file
70
5-close-channels/main.go
Normal file
@ -0,0 +1,70 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
@Ref: https://livebook.manning.com/book/go-in-practice/chapter-3/65
|
||||
*/
|
||||
|
||||
func main() {
|
||||
msg := make(chan string)
|
||||
done := make(chan bool)
|
||||
until := time.After(5 * time.Second)
|
||||
|
||||
go send(msg, done)
|
||||
|
||||
for {
|
||||
select {
|
||||
case m := <-msg:
|
||||
fmt.Println(m)
|
||||
case <-until:
|
||||
done <- true
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func send(ch chan<- string, done <-chan bool) {
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
fmt.Println("done")
|
||||
close(ch)
|
||||
return
|
||||
default:
|
||||
ch <- "Hello"
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Improper channel close
|
||||
// func main() {
|
||||
// msg := make(chan string)
|
||||
// until := time.After(5 * time.Second)
|
||||
|
||||
// go send(msg)
|
||||
|
||||
// for {
|
||||
// select {
|
||||
// case m := <-msg:
|
||||
// fmt.Println(m)
|
||||
// case <-until:
|
||||
// close(msg)
|
||||
// time.Sleep(500 * time.Millisecond)
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// func send(ch chan string) {
|
||||
// for {
|
||||
// ch <- "hello"
|
||||
// time.Sleep(500 * time.Millisecond)
|
||||
// }
|
||||
// }
|
28
6-lock-with-channel/main.go
Normal file
28
6-lock-with-channel/main.go
Normal file
@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
@Ref: https://livebook.manning.com/book/go-in-practice/chapter-3/65
|
||||
*/
|
||||
|
||||
func main() {
|
||||
lock := make(chan bool, 1)
|
||||
for i := 1; i < 7; i++ {
|
||||
go worker(i, lock)
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
|
||||
func worker(id int, lock chan bool) {
|
||||
fmt.Printf("%d wants the lock\n", id)
|
||||
lock <- true
|
||||
fmt.Printf("%d has the lock\n", id)
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
fmt.Printf("%d is releasing the lock\n", id)
|
||||
<-lock
|
||||
}
|
19
interview-questions.md
Normal file
19
interview-questions.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Interview Questions
|
||||
|
||||
|
||||
This doc is not a buntch of real questions from interview. It is more about the different concept in golang programming that could be asked by interviewers.
|
||||
|
||||
## 1. What is goroutines?
|
||||
|
||||
Goroutine, for me, I understand it as a detached process. It can run independently of the function that started it.
|
||||
|
||||
## 2. What is channels?
|
||||
|
||||
A channel is a pipeline for sending and receiving data. It is like a socket that runs inside your program. It provides a way for one goroutine to send structured data to another.
|
||||
|
||||
## 3. What is wait group?
|
||||
|
||||
|
||||
|
||||
## 4. Race condition
|
||||
In a rece condition, two things are "racing" to use the same piece of data. Problems arise when both are working with the same data at around the same time. One goroutine may be only partway through modifying a value when another goroutine tries to use it. And that situation can have unintended consequences.
|
Loading…
Reference in New Issue
Block a user