Then yesterday, said today mainly concurrent security, lock and two simple web example
1. concurrent security and lock
Since it comes to security, it would be unsafe to talk about why. Yesterday said goroutine concurrency, so if multiple goroutine access when there is no synchronization with each other at the same time a resource and performs i / o operations, and that this time we called them at a competitive state, is referred to as a race. Let's look at the example of a race
package main
import (
"fmt"
"runtime"
"sync"
)
var (
count int //定义一个全局变量,之后会对它进行操作
wg1 sync.WaitGroup
)
func incCounter(id int) {
defer wg1.Done()
for i := 0; i < 2; i++ {
value := count
runtime.Gosched()
value++
count = value
}
}
func main() {
wg1.Add(2)
go incCounter(1)
go incCounter(2)
wg1.Wait()
fmt.Println("最后的count值为:", count)
}
Analyze, obviously with the two goroutine, and each goroutine will be performed twice, the results should not be 4 right? Why is 2. This time it comes to race, that is, each goroutine will cover the operation of other goroutine, so there have been errors. This time the importance of the lock is manifested, of course, we can also use atomic function to eliminate the influence of race, but it only supports a few built-in primitive data types, so the lock is the most critical. The most commonly used is the mutex (mutex), it can guarantee the same time only a goroutine can access the resource, and then mutex to modify the code above to see the effect.
package main
import (
"fmt"
"runtime"
"sync"
)
var (
count int //定义一个全局变量,之后会对它进行操作
wg1 sync.WaitGroup
mutex sync.Mutex
)
func incCounter(id int) {
defer wg1.Done()
for i := 0; i < 2; i++ {
mutex.Lock()
value := count
runtime.Gosched()
value++
count = value
mutex.Unlock()
}
}
func main() {
wg1.Add(2)
go incCounter(1)
go incCounter(2)
wg1.Wait()
fmt.Println("最后的count值为:", count)
}
Plus the result of a mutex
so normal, so mutex can be a good race to prevent the problem.
When a read operation is much greater than the write operation, with a simple mutex is not very wasteful, this time there is a read-write mutex
package main
import (
"fmt"
"sync"
"time"
)
//读写互斥锁:读的次数远远大于写的次数
var (
x1 int64
wg1 sync.WaitGroup
lock1 sync.Mutex //互斥锁
rwlock sync.RWMutex //读写互斥锁
)
func read() {
//lock1.Lock()
rwlock.RLock()
time.Sleep(time.Millisecond)
//lock1.Unlock()
rwlock.RUnlock()
wg1.Done()
}
func write() {
//lock1.Lock()
rwlock.Lock()
x1 += 1
time.Sleep(time.Millisecond * 10)
//lock1.Unlock()
rwlock.Unlock()
wg1.Done()
}
func main() {
start := time.Now()
for i := 0; i < 1000; i++ {
wg1.Add(1)
go read()
}
for i := 0; i < 10; i++ {
wg1.Add(1)
go write()
}
wg1.Wait()
fmt.Println(time.Now().Sub(start))
}
//sync.Once 只运行一次
//sync.Map 并发安全的map并且是空接口类型,Store、Load、LoadorStore、Delete、Range
With this example will find the number in the case of reading is far greater than the number of write and read-write mutex speed will be much faster than using a mutex.
Examples of 2.web
The 1.web "HELLO WORLD"
package main
import (
"fmt"
"net/http"
)
func handle(write http.ResponseWriter, request *http.Request) {
fmt.Fprintf(write, "hello world,%s!", request.URL.Path[1:])
}
func main() {
http.HandleFunc("/", handle)
http.ListenAndServe(":8081", nil)
Code is very simple, is to set the port to start your web service, then print hello world and the URL information of port
2. A simple server and client communications
server
package main
import (
"bufio"
"fmt"
"net"
)
//tcp server demo
func process(conn net.Conn) {
defer conn.Close()
for {
reader := bufio.NewReader(conn)
var buf [128]byte
n, err := reader.Read(buf[:])
if err != nil {
fmt.Printf("read from conn failed,err:%v\n", err)
break
}
recv := string(buf[:n])
fmt.Println("接收到的数据为:", recv)
conn.Write([]byte("ok"))
}
}
func main() {
listen, err := net.Listen("tcp", "127.0.0.1:20000")
if err != nil {
fmt.Printf("listen failed,err:%v\n", err)
return
}
for {
conn, err := listen.Accept()
if err != nil {
fmt.Printf("accept failed,err:%v\n", err)
continue
}
go process(conn)
}
}
Client
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
//1.与服务端建立连接
conn, err := net.Dial("tcp", "127.0.0.1:20000")
if err != nil {
fmt.Printf("dial failed,err:%v\n", err)
return
}
//2.利用连接发送接收数据
input := bufio.NewReader(os.Stdin)
for {
s, _ := input.ReadString('\n')
s = strings.TrimSpace(s)
if strings.ToUpper(s) == "Q" {
return
}
//给服务端发消息
_, err := conn.Write([]byte(s))
if err != nil {
fmt.Printf("senf failed,err:%v\n", err)
return
}
//从服务器接受回复的消息
var buf [1024]byte
n, err := conn.Read(buf[:])
if err != nil {
fmt.Printf("read failed,err:%v\n", err)
return
}
fmt.Println("收到服务端回复:", string(buf[:n]))
}
}
The result:
in fact mainly use web development framework, like the python flask, django ...... java of ssm, ssh ...... so go out web language, then also use the framework, so recently will go to learn the knowledge of gin .