in Go, each concurrently executing activity called a groutine
when a program starts, it has a groutine that calls the
Main function, we call it
Goroutines have no notion of identity that is accessible to the programmer
the Go runtime contains its own scheduler that uses a technique known as m:n scheduling. because
it multiplexes (or schedules) m goroutines on n OS threads. the job of the Go scheduler is analogous to that of the kernel scheduler. but it is
concerned only with the goroutines of a single Go program.
Go scheduler is
not invoked periodically by a hardware timer, for example, when a goroutine calls time.Sleep or blocks in a channel or mutex operation, the scheduler puts it to sleep and runs another goroutine until it is time to wake the first one up.
rescheduling a groutine is much cheaper than rescheduling a thread.
goroutines that are sleeping or blocked in communication do not need a thread at all.
Go scheduler uses a parameter called GOMAXPROCS to determine how many OS threads may be actively executing Go code simultaneously.
default value is the number of CPUs on the machine.
$ GOMAXPROCS=1 go run hacker-cliché.go
$ GOMAXPROCS=2 go run hacker-cliché.go
in the first run, at most one groutine was executed at a time. initially, it was the main groutine, which prints 1, after a period of time, the Go scheduler put it to sleep and woke up the goroutine that prints 0, giving it a turn to run on the OS thread.
when a goroutine gotten stuck,cause it’s trying to send their responses on a channel from which no goroutine will ever receive. this situation, called a goroutine leak
leak goroutines are not automatically collected, it's important to make sure that goroutines terminate themselves when no longer needed
when we cannot confidently say that one event
happens before the other, then the events x and y are
concurency-safe: a function that works correctly in a sequential program even when called concurrently.
there are many reasons a function might not work when called concurrently, including
a race condition is a situation in which the program does not give the correct result for some interleavings of the operations of multiple goroutines.
to avoice data race
- avoid accessing the variable from multiple groutines(channel)
- initialize variable before creating additional groutines, and never modify it again.
f() // call f(); wait for it to return
go f() // create a new goroutine that calls f(); don't wait
Main functionreturns, all groutines will abruptly terminate
- apart of
Main functionreturns, no other way to stop groutines
communication mechanism that lets one goroutine send values to another goroutine. connections between goroutines
ch := make(chan int) // unbuffered cahnnel
ch = make(chan int, 0) // unbuffered channel
ch = make(chan int, 3) // buffered channel with capacity 3
ch <- "data" // a send statement
x := <- ch // a receive expression in an assignment statement
<-ch // a rece expression; result is discarded
close(ch) // close channel that no more values will ever be sent on this channel
a send operation on an unbuffered channel blocks the sending goroutine until another goroutine executes a corresponding receive on the same channel.
unbuffered channels give stronger synchronization guarantees because every send operation is synchronized with its corresponding receive
Channels can be used to connect goroutines together so that the output of one is the input to another. this is called a pipeline
- Program will panic when Channel stop sending data but didn’t closed
- When Channel closed but receiver still receiving data, it will get empty data
- use range statement to receive data from a channel that will closed
Unidirectional Channel Types
buffered has a queue of elements. a send operation on a buffered channel interts an element at the back of the queue, also receive operation removes an element from the front. if the channel is full, the send operation blocks its goroutine until space is made available by another goroutines’s receive. Conversely, if the cahnnel is empty a receive operation blocks until a value is sent by another goroutine
buffered channels these operations between send / receive are decoupled, also got upper bound on the number of values that will be sent on a channel, failure to allocate sufficient buffer capacity would cause the program to dead lock
- Add(int) add increments the counter
- Done() equivalent Add(-1)
Mutual Exclusion Lock
mu sync.Mutex // lock