一、Go并发
1、Go两种并发编程模型
Go语言中的并发程序可以用两种手段来实现:
第8章:基于Goroutines和Channels的并发
- 第8章讲解goroutine和channel,其支持“顺序通信进程”(communicating sequential processes)或被简称为CSP。
- CSP是一种
现代的并发编程模型
,在这种编程模型中值会在不同的运行实例(goroutine)中传递,尽管大多数情况下仍然是被限制在单一实例中。
第9章:基于共享变量/内存的并发
更传统并发编程模型,多线程共享内存
。如果你在其它的主流语言中写过并发程序的话可能会更熟悉一些。- 第9章也会深入介绍一些并发程序带来的风险和陷阱。
- 尽管Go对并发的支持是众多强力特性之一,但跟踪调试并发程序还是很困难,在线性程序中形成的直觉往往还会使我们误入歧途。
2、基于goroutine的并发
(1)goroutine本质
(2)goroutine特点
(3)区分:goroutine vs 多线程
Java/C++ 的多线程是手动管理的,需要开发者维护一个线程池,手动包装一个又一个任务,并且需要手动调度线程。
代码里调用操作系统的接口,创建线程、切换线程。
Go的多线程是自动管理的,在用户态模拟多线程。goroutine就是这样一种机制,程序员只需要自己定义任务,系统自动帮助我们把任务分配到CPU上并发执行。
Go语言自己在用户的runtime里面,自己实现了一堆用户态的线程,也就是用程序模拟的线程。这些线程最终会调用操作系统线程。切换时,Go语言是自动切换。
Go的并发通过goroutine实现,goroutine相当于线程,属于用户态的线程。
goroutine很轻量级,轻轻松松开十几万个并发工作。Java中的一个线程至少占用2M的空间,开1000个线程就至少要2G空间,16G内存最多也就8k个线程,十几万个早崩了。
3、基于共享变量的并发
二、Go多线程通信实现
参考:
并发的clock服务(服务器向客户端写):https://docs.hacknode.org/gopl-zh/ch8/ch8-02.html
多线程服务端和客户端通信(客户端向服务器写):https://blog.51cto.com/u_15144024/2858043
1、功能
多个客户端,向服务器请求时钟,
①服务器回复当前日期时间。
②服务器每隔一秒钟发送一次当前时间。
③服务器每个整点报时。
2、代码
①服务器回复当前日期时间。
func Test14() {
p := "8888"
go clockServer(1, p)
// 单客户端
log.Println("client:", clockClient(p))
// 多客户端
go func() {
for i := 1; i < 4; i++ {
time.Sleep(3 * time.Second)
log.Println("client", i, ":", clockClient(p))
}
}()
time.Sleep(1 * time.Minute) //睡1分钟,保证前面的线程都执行完了,否则可能没执行完就被主线程强行终止了。
}
②服务器每隔一秒钟发送一次当前时间。
func Test15() {
p := "8888"
go clockServer(2, p)
// 单客户端
log.Println("client:", clockClient(p))
}
③服务器每个整点报时。
公共代码:
func clockClient(port string) (result string) {
conn, err := net.Dial("tcp", "localhost:"+port)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
// 服务器向客户端写
buf := make([]byte, 128)
_, err = io.CopyBuffer(os.Stdout, conn, buf) //同上,加个buffer
// _, err = conn.Read(buf) //读。读出来后conn里就没有了。【这个不能用??】
if err != nil {
log.Fatal(err)
}
log.Println("服务器发过来的当前时间:", string(buf))
return string(buf)
}
func clockServer(serverType int, port string) {
listener, err := net.Listen("tcp", "localhost:"+port)
if err != nil {
log.Fatal(err)
}
defer listener.Close()
switch serverType {
case 1:
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal(err)
}
t := time.Now().Format("Mon Jan 2 15:04:05")
_, err = conn.Write([]byte(t))
if err != nil {
return
}
}
case 2:
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal(err)
}
defer conn.Close()
for i := 0; i < 3; i++ { // 一个线程服务3秒钟,然后换下一个线程
t := time.Now().Format("Mon Jan 2 15:04:05\n")
_, err = conn.Write([]byte(t))
// _, err := io.WriteString(conn, t) // 同上
if err != nil {
return
}
time.Sleep(1 * time.Second)
}
}
case 3:
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal(err)
}
for { //这如果不是监听的话,就一直占着CPU吧??这不是死等吗?有问题吧?
t := time.Now().Format("Mon Jan 2 15:04:05")
// m := time.Now().Minute()
s := time.Now().Second()
// if m == 0 && s == 0 { //整时
if s == 0 { //整分
_, err = conn.Write([]byte(t))
if err != nil {
return
}
}
// time.Sleep(1 * time.Minute)
}
}
}
}
作者:西伯尔
出处:http://www.cnblogs.com/sybil-hxl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。