2.7 并发编程

go协程

golang 通过一个go关键字就可以开启一个协程。

func main() {
//两个交错输出
go sayHello()
go sayHello2()
time.Sleep(time.Second * 3) //阻塞主线程
} func sayHello() {
for i := 0; i < 30; i++ {
fmt.Println("hello world")
}
} func sayHello2() {
for i := 0; i < 30; i++ {
fmt.Println("你好中国")
}
}
//通过sync.WaitGroup来等待所有线程完成
package main import (
"fmt"
"sync"
) func main() {
var w = &sync.WaitGroup{}
w.Add(2)
go sayEn(w)
go sayZh(w)
w.Wait()
} func sayEn(w *sync.WaitGroup) {
for i := 0; i < 30; i++ {
fmt.Println("hello world")
}
w.Done() //每当这个方法完成则减少1
} func sayZh(w *sync.WaitGroup) {
for i := 0; i < 30; i++ {
fmt.Println("中国你好")
}
w.Done() //每当这个方法完成则减少1
}

go管道

管道的定义:

//无缓冲管道
flag := make(chan bool)
//有缓冲管道
data := make(chan int, 10)
//向管道中添加值
data <- 10
//从管道中取值
agr := <- data
<- data //也可以直接释放值,不用变量接收

1. 通过go实现同步

package main

import (
"fmt"
) func main() {
w1, w2 := make(chan bool), make(chan bool)
go sayEn_chan(w1)
go sayZh_chan(w2)
<- w1 //阻塞,直到chan 可以取出数据
<- w2
} func sayEn_chan(w chan bool) {
for i := 0; i < 30; i++ {
fmt.Println("hello world")
}
w <- true //方法完成写入通道
} func sayZh_chan(w chan bool) {
for i := 0; i < 30; i++ {
fmt.Println("中国你好")
}
w <- true
}

2. 正确处理累加

package main

import (
"fmt"
"sync/atomic"
) var (
count int64
) func main() {
w1, w2 := make(chan bool), make(chan bool)
go add(w1)
go add(w2)
<- w1 //阻塞,直到chan 可以取出数据
<- w2
fmt.Println(count)
} func add(w chan bool) {
for i := 0; i < 5000; i++ {
atomic.AddInt64(&count, 1)
}
w <- true
}

3. 通道实现数据共享

package main

import (
"fmt"
"math/rand"
"sync"
) var wg sync.WaitGroup func main() {
count := make(chan int)
wg.Add(2)
go player("张三", count)
go player("李四", count)
//发球
count <- 1
wg.Wait() //阻塞等待2个线程完成
} func player(name string, count chan int) {
defer wg.Done() for {
i, ok := <-count if !ok { //通道关闭
fmt.Printf("运动员 %s 赢了\n", name)
return
} tmp := rand.Intn(100)
if tmp % 13 == 0 { //没有接到球
fmt.Printf("运动员 %s 输了\n", name)
close(count)
return
}
fmt.Printf("运动员 %s 击球 %d \n", name , i)
i ++
count <- i
}
}

4. 缓冲管道

package main

import (
"fmt"
"sync"
"time"
) var (
numberTasks = 10
workers = 4
) var wg2 sync.WaitGroup func main() {
wg2.Add(workers)
tasks := make(chan int, numberTasks) for i := 0; i < workers; i++ {
go work(tasks, i)
} for j := 1; j <= numberTasks; j++ {
tasks <- j
}
close(tasks) wg2.Wait()
} func work(tasks chan int, worker int) {
defer wg2.Done()
for {
task, ok := <- tasks
if !ok {
fmt.Printf("任务完成,工号:%d\n", worker)
return
}
fmt.Printf("工号:%d, 开始工作:%d\n", worker, task)
time.Sleep(time.Microsecond * 100)
fmt.Printf("工号:%d, 完成工作:%d\n", worker, task) } }

5. select

select 的特点是:不会阻塞,哪个管道有值,我取哪个。所以,下面当运行到go的时候,a,b还没有添值,所以只能选择defaul运行,这里可以把defualt部分和b<-2去掉,select会被阻塞,直到a<-1执行

func main() {
a := make(chan int)
b := make(chan int)
go func() {
b <- 2
time.Sleep(time.Second * 3)
a <- 1
}()
select {
case <- a:
fmt.Println("a")
case <- b:
fmt.Println("b")
time.Sleep(time.Second * 3)
default:
fmt.Println("hello world")
}
}

6. runner并发模型

package runner

import (
"errors"
"os"
"os/signal"
"time"
) type Runner struct {
interrupt chan os.Signal complete chan error timeout <-chan time.Time //声明一个只读的管道 tasks []func(int)
} var ErrorTimeout = errors.New("receive timeout") var ErrorInterrupt = errors.New("interrupt error") func New(duration time.Duration) *Runner {
return &Runner{
interrupt: make(chan os.Signal, 1),
complete: make(chan error),
timeout: time.After(duration),
}
} func (r *Runner) Add(tasks...func(int)) {
r.tasks = append(r.tasks, tasks...)
} func (r *Runner) getInterrupt() bool {
select {
case <-r.interrupt:
signal.Stop(r.interrupt)
return true
default:
return false
}
} func (r *Runner) run() error {
for id, task := range r.tasks {
if r.getInterrupt() {
return ErrorInterrupt
}
task(id)
}
return nil
} func (r *Runner) Start() error {
signal.Notify(r.interrupt, os.Interrupt)
go func() {
r.complete <- r.run()
}() select {
case err := <- r.complete:
return err
case <- r.timeout:
return ErrorTimeout
}
}

测试

package main

import (
"gorounting/runner"
"log"
"os"
"time"
) const (
timeout = 4 * time.Second
) func main() {
log.Println("任务开始")
ru := runner.New(timeout)
ru.Add(createTask(), createTask(), createTask(), createTask()) if err := ru.Start(); err != nil {
switch err {
case runner.ErrorInterrupt:
log.Println("系统被中断")
os.Exit(1)
case runner.ErrorTimeout:
log.Println("系统超时")
os.Exit(2) }
}
log.Println("程序结束") } func createTask() func(int) {
return func(id int) {
log.Printf("process-task #%d\n", id)
time.Sleep(time.Duration(id) * time.Second )
}
}

golang总结-并发的更多相关文章

  1. golang的并发

    Golang的并发涉及二个概念: goroutine channel goroutine由关键字go创建. channel由关键字chan定义 channel的理解稍难点, 最简单地, 你把它当成Un ...

  2. golang的并发不等于并行

    先 看下面一道面试题: func main() { runtime.GOMAXPROCS(1) wg := sync.WaitGroup{} wg.Add(20) for i := 0; i < ...

  3. go---weichart个人对Golang中并发理解

    个人觉得goroutine是Go并行设计的核心,goroutine是协程,但比线程占用更少.golang对并发的处理采用了协程的技术.golang的goroutine就是协程的实现. 十几个gorou ...

  4. golang实现并发爬虫三(用队列调度器实现)

    欲看此文,必先可先看: golang实现并发爬虫一(单任务版本爬虫功能) gollang实现并发爬虫二(简单调度器) 上文中的用简单的调度器实现了并发爬虫. 并且,也提到了这种并发爬虫的实现可以提高爬 ...

  5. 【GoLang】并发小结

    006.并发 1 概念 1.1 goroutine是Go并行设计的核心,goroutine的本质是轻量级线程 1.2 golang的runtime实现了对轻量级线程即goroutine的智能调度管理 ...

  6. golang高并发的理解

    前言 GO语言在WEB开发领域中的使用越来越广泛,Hired 发布的<2019 软件工程师状态>报告中指出,具有 Go 经验的候选人是迄今为止最具吸引力的.平均每位求职者会收到9 份面试邀 ...

  7. Golang之并发篇

    进程和线程 A.进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位. B.线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位. C.一 ...

  8. golang中并发的相关知识

    golang中done channel理解:https://segmentfault.com/a/1190000006261218 golang并发模型之使用Context:https://segme ...

  9. golang中并发sync和channel

    golang中实现并发非常简单,只需在需要并发的函数前面添加关键字"go",但是如何处理go并发机制中不同goroutine之间的同步与通信,golang 中提供了sync包和channel ...

随机推荐

  1. Alaya Webdav Server 0.0.10 发布

    Alaya Webdav Server 0.0.10 修复了很多 bug,Webdav 'Copy' 可以使用了. Alaya 是一个提供 WebDAV 支持的 Web 服务器,支持 HTTPS 和 ...

  2. mvn install 时候报GBK编码错误解决办法

    在pom.xml里面 <properties> <!-- 文件拷贝时的编码 --> <project.build.sourceEncoding>UTF-</p ...

  3. 个人总结-7- 实现图片在MySQL数据库中的存储,取出以及显示在jsp页面上

    昨天主要是进行对数据库的内容提取出来并进行动态显示,这个只需要设置一个servlet从数据库中获取数据即可,只是图片比较特殊,不能显示. 今天准备继续找方法来实现图片得录入和显示到jsp中,准备从网上 ...

  4. android 实现微信分享多张图片的功能

    昨天公司老大通知客户改需求了,原来的微信分享改成分享多张图片,然后屁颠屁颠跑到微信平台看了以后 心里千万只草泥马狂奔而过,微信平台没有提供分享多张的SDK有木有啊,我们只能自己调用系统自带的分享功能实 ...

  5. 彻底澄清c/c++指针概念

    传统的指针概念教科书上已经写的很详细了,这里作为一些补充 在声明一个指针变量的时候 double  *ptr: 这是声明了一个ptr的指针变量,ptr本身是地址,它的数据类型是double  *,在变 ...

  6. Oracle案例08——xx.xx.xx.xx,表空间 SYSAUX 使用率>95%%

    本实例主要针对Oracle表空间饱满问题处理方法做个步骤分享.  一.告警信息 收到zabbix告警信息,表空间 SYSAUX 使用率>95%%,系统表空间sysaux使用率超过了95%. 二. ...

  7. Linux下调节CPU使用的几种方法

    一,使用taskset充分利用多核cpu,让cpu的使用率均衡到每个cpu上 #taskset-p,    设定一个已存在的pid,而不是重新开启一个新任务-c,    指定一个处理,可以指定多个,以 ...

  8. 企业级Apache详解2

    http_conf主配置说明 root@lamp01 apache]# grep -Ev "#|^$" conf/httpd.conf DocumentRoot "/us ...

  9. HTTP协议图--HTTP 报文首部之请求行、状态行

    1.请求行 举个栗子,下面是一个 HTTP 请求的报文: GET /index.htm HTTP/1.1 Host: sample.com 其中,下面的这行就是请求行, GET /index.htm ...

  10. 内网渗透之IPC,远程执行

    开启服务 net start Schedule net start wmiApSrv 关闭防火墙 net stop sharedaccess net use \\目标IP\ipc$ "&qu ...