Compiled from http://golang.org/doc/effective_go.html#concurrency (translation error, please correct me)
1. Share by communicating ):
Do not communicate by sharing memory; instead, share memory by communicating.
Do not communicate through Memory sharing; Share the memory through communication. Using channels to control variable access makes it easier to write clear and correct programs.
2. Goroutines:
Why create a new word called goroutine? The reason is that the existing terms, such as threads, coroutines, and Processes, cannot accurately express the meaning they want to express (the translator is not recommended to translate it into Chinese here, because there is no word in Chinese to express its meaning accurately ). A Goroutine is a function that is executed in parallel with other goroutine in the same address space. This sentence is a bit difficult, but it indicates two meanings: A goroutine is a function; multiple goroutines are executed in parallel in the same address space.
Goroutine is lightweight and consumes much less memory than the method for directly allocating stack space. Its starting stack (stack) is very small, and memory usage is increased by allocating (and releasing) heap space as needed.
Goroutine can be reused by multiple OS threads. Therefore, if a goroutine is blocked (such as waiting for I/O), other threads can continue to run. This design hides the complexity of thread creation and thread management.
You can call the function in a new goroutine by adding the keyword go before a function or method. After the call is complete, the goroutine exits. (The effect is similar to running the command in the background after running the command in the Unix Shell &).
Go list. Sort () // run list. Sort in parallel without waiting for its end.
Anonymous functions are also useful in goroutine calls.
Func Announce (message string, delay int64 ){
Go func (){
Time. Sleep (delay)
Fmt. Println (message)
} () // Note the brackets. You must call this function.
}
In the Go language, an anonymous function is a closure (closure), which ensures that the lifetime of the variables referenced by the function is as long as that of the function.
This example is not practical, because the function does not signal at the end of the operation. So we need a channel.
3. Channel)
Like map, the channel is a reference type. Use make to allocate memory. If an optional integer parameter is provided when make is called, the channel will be allocated a buffer of the corresponding size. The default buffer size is 0, corresponding to no buffer channel or synchronous channel.
Ci: = make (chan int) // no buffer integer Channel
Cj: = make (chan int, 0) // no buffer integer Channel
Cs: = make (chan * OS. File, 100) // cached File pointer Channel
The channel combines communication (value exchange) and synchronization to ensure that both computing processes (goroutine) are in a known state.
The background parallel sorting is used as an example. Channels can be used to wait for the running goroutine to be sorted.
C: = make (chan int) // Allocate a channel.
// Start sorting in goroutine. When sorting is complete, signals are sent on the channel.
Go func (){
List. Sort ()
C <-1 // send a signal. The value does not matter.
}()
DoSomethingForAWhile ()
<-C // wait until the sorting is complete and discard the sent value.
The recipient (receivers) will be blocked until the data is received. If the channel is not buffered, the sender (sender) is blocked until the receiver receives the data. If the channel has a buffer, the sender is blocked only when the data is filled in the buffer. If the buffer is full, the sender will wait for a receiver to take a value.
The buffered channel can be used like a signal lamp, for example, to limit the throughput. In the following example, the incoming request is passed to handle. handle sends a value to the channel, processes the request, and finally receives a value from the channel. The channel buffer size limits the number of concurrently called processes.
VaR SEM = make (Chan int, maxoutstanding)
Func handle (R * request ){
SEM <-1 // The waiting queue buffer is not full.
Process (r) // process the request, which may take a long time.
<-SEM // The request processing is complete. Prepare to process the next request.
}
Func serve (queue chan * request ){
For {
Req: = <-queue
Go handle (req) // do not wait for handle to complete
}
}
By starting a fixed number of handle goroutines, you can also implement the same function. These goroutines read requests from the request channel. The number of Goroutines limits the number of concurrently called processes. The Serve function also receives the exit signal from a channel. After goroutines is started, it is blocked until it receives the exit signal:
Func handle (queue chan * request ){
For R: = range queue {
Process (r)
}
}
Func Serve (clientRequests chan * clientRequests, quit chan bool ){
// Initiate request processing
For I: = 0; I <MaxOutstanding; I ++ {
Go handle (clientRequests)
}
<-Quit // wait for the exit Signal
}
4. Channels of channels)
One of the most important features of Go is that channels can be allocated and transmitted like other types of values. This feature is often used for secure and parallel demultiplexing (demultiplexing ).
In the preceding example, handle is an idealized request processing function, but we do not define the specific types of requests that it can process. If this type includes a channel, each client can provide its own response method.
Type request struct {
ARGs [] int
F func ([] INT) int
Resultchan Chan int
}
The client provides a function, function parameters, and a channel for the request object to receive the response.
Func sum (A [] INT) (s int ){
For _, V: = range {
S + = V
}
Return
}
Request: = & Request {[] int {3, 4, 5}, sum, make (chan int )}
// Send the request
ClientRequests <-request
// Wait for response.
Fmt. Printf ("answer: % d \ n", <-request. resultChan)
On the server side, the request processing function is
Func handle (queue chan * request ){
For Req: = range queue {
Req. resultchan <-req. F (req. ARGs)
}
}
Obviously there is still a lot of work to do to make this example more practical, but this is a framework for speed restrictions, parallelism, and non-blocking RPC systems, and there is no mutex in it.
5. Parallelization)
Another application of these ideas is the use of multi-core CPUs for parallel computing. If the computing process can be divided into multiple segments, it can be parallelized in this way: after each segment is complete, it sends signals through the channel.
Suppose we have a time-consuming vector operation, and the values after each data item operation are independent, as shown in the following ideal example:
Type Vector [] float64
// Apply to v [I], v [I + 1]... v [n-1].
Func (v Vector) DoSome (I, n int, u Vector, c chan int ){
For; I <n; I ++ {
V [I] + = u. Op (v [I])
}
C <-1 // sending completion Signal
}
We start an Independent Computing segment for each CPU in a loop. These segments can be executed in any order, and the execution sequence is irrelevant here. After starting all the goroutines, we only need to extract all the completion signals from the channel.
Const ncpu = 4 // Number of CPU Cores
Func (V vector) doall (U vector ){
C: = make (Chan int, ncpu) // buffering optional but sensible.
For I: = 0; I <ncpu; I ++ {
Go v. dosome (I * Len (v)/ncpu, (I + 1) * Len (v)/ncpu, U, c)
}
// Retrieve all signals from the Channel
For I: = 0; I <ncpu; I ++ {
<-C // wait for a task to complete
}
// All tasks have been completed.
}
By default, the current implementation of the Go compiler gc (6 GB) does not make the code parallel. For user-level processes, it only uses single-core. Any number of goroutines can be blocked in system calls, but by default, only one goroutine can execute user-level code at any time. If you need multi-core CPU Parallel Computing, you must notify the number of goroutines executed in parallel at runtime, that is, GOMAXPROCS. There are two ways to set GOMAXPROCS: one is to set the environment variable GOMAXPROCS to the number of CPU cores; the other is to import the runtime package and call runtime. GOMAXPROCS (NPCU ).
(Author: mahaohe. Respect the fruits of others' work. repost the results with the author or source)