Golang之并发篇
进程和线程 A。进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。 B。线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。 C。一个进程可以创建和撤销多个线程;同一进程中的多个线程之间可以并发执行。
并发和并行
并发:多线程程序在一个核的cpu上运行
并行:多线程程序在多个核的cpu上运行
举例。。一个妈给一个碗给多个小孩喂饭,,是并发
一个妈给每个小孩一人一个碗,就是并行
并发 并行
协程和线程
协程:独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级协程,这些用户级线程的调度也是自己实现的。
线程:一个线程上可以跑多个协程,协程是轻量级的线程。
例子
package main import (
"fmt"
"time"
) func test() {
var i int
for {
fmt.Println(i)
time.Sleep(time.Second)
i++
}
}
func main() {
go test() //起一个协程执行test()
for {
fmt.Println("i : runnging in main")
time.Sleep(time.Second )
}
}
-
--
设置Golang运行的cpu核数。
1.8版本以上,默认跑多个核
package main import (
"fmt"
"runtime"
) func main() {
num := runtime.NumCPU()
runtime.GOMAXPROCS(num)
fmt.Println(num)
}
并发计算
package main import (
"fmt"
"sync"
"time"
) var (
m = make(map[int]uint64)
lock sync.Mutex
) type task struct {
n int
} func calc(t *task) {
var sum uint64
sum =
for i := ; i < t.n; i++ {
sum *= uint64(i)
}
fmt.Println(t.n, sum)
lock.Lock()
m[t.n] = sum
lock.Unlock() } func main() {
for i := ; i < ; i++ {
t := &task{n: i}
go calc(t)//并发执行,谁快谁先出
}
time.Sleep( * time.Second)
//lock.Lock()
//for k, v := range m {
// fmt.Printf("%d!=%v\n", k, v)
//}
//lock.Unlock()
}
并发计算
Channel
channel概念
a。类似unix中的管道(pipe)
b.先进先出
c。线程安全,多个goroutine同时访问,不需要枷锁
d。channel是有类型的,一个整数的channel只能存整数
channel声明
var name chan string
var age chan int
var mapchan chan map[string]string
var test chan student
var test1 chan *student
channel初始化
使用make进行初始化
var test chan int
test = make(chan int,) var test chan string
test=make(chan string,)
channel基本操作
从channel读取数据
var testChan chan int
testChan = make(chan int, )
var a int
a = <-testChan
-从channel写入数据
var testChan chan int
testChan = make(chan int, )
var a int =
testChan <- a
第一个例子
package main import "fmt" type student struct {
name string
} func main() {
var stuChan chan *student
stuChan = make(chan *student, ) stu := student{name: "stu001"} stuChan <- &stu var stu01 interface{}
stu01 = <-stuChan var stu02 *student
stu02, ok := stu01.(*student)
if !ok {
fmt.Println("can not convert")
return
}
fmt.Println(stu02)
}
goroutine与channel
package main import (
"fmt"
"time"
) //起一个读的协程
func write(ch chan int) {
for i := ; i < ; i++ {
ch <- i
}
} func read(ch chan int) {
for {
var b int
b = <-ch
fmt.Println(b)
}
} func main() {
intChan := make(chan int, )
go write(intChan)
go read(intChan)
time.Sleep( * time.Second)
}
读,取,字符串
package main import (
"fmt"
"time"
) func sendData(ch chan string) {
ch <- "Washington"
ch <- "Tripoli"
ch <- "London"
ch <- "Beijing"
ch <- "Tokio"
} func getData(ch chan string) {
var input string
for {
input = <-ch
fmt.Println(input)
}
} func main() {
ch := make(chan string)
go sendData(ch)
go getData(ch)
time.Sleep( * time.Second)
}
读取字符串
Channel缓冲区
只能放一个元素的testChan
var testChan chan int
testChan = make(chan int)
var a int
a = <-testChan
-
testChan是带缓冲区的chan,一次可以放10个元素
var testChan chan int
testChan = make(chan int, )
var a int =
testChan <- a
-
package main import (
"fmt"
"sync"
"time"
) var (
m = make(map[int]uint64)
lock sync.Mutex
) type task struct {
n int
} func calc(t *task) {
var sum uint64
sum =
for i := ; i < t.n; i++ {
sum *= uint64(i)
}
fmt.Println(t.n, sum)
lock.Lock()
m[t.n] = sum
lock.Unlock()
} func main() {
for i := ; i < ; i++ {
t := &task{n: i}
go calc(t)
}
time.Sleep( * time.Second)
lock.Lock()
for k, v := range m {
fmt.Printf("%d!=%v\n", k, v) }
lock.Unlock()
}
goroutine_lock
package main import (
"fmt"
) func calc(taskChan chan int, resChan chan int, exitChan chan bool) {
for v := range taskChan {
flag := true
for i := ; i < v; i++ {
if v%i == {
flag = false
break
}
}
if flag {
resChan <- v
}
}
fmt.Println("exit")
exitChan <- true
}
func main() {
intChan := make(chan int, )
resultChan := make(chan int, )
exitChan := make(chan bool, )
go func() {
for i := ; i < ; i++ {
intChan <- i
}
close(intChan)
}()
for i := ; i < ; i++ {
go calc(intChan, resultChan, exitChan)
} //等待所有计算的goroutine全部退出
go func() {
for i := ; i < ; i++ {
<-exitChan
fmt.Println("wait goroute", i, "exited")
}
close(resultChan)
}()
for v := range resultChan {
fmt.Println(v)
} }
goroutine_sync
package main import "fmt" func send(ch chan int, exitChan chan struct{}) {
for i := ; i < ; i++ {
ch <- i
}
close(ch)
var a struct{}
exitChan <- a
}
func recv(ch chan int, exitChan chan struct{}) {
for {
v, ok := <-ch
if !ok {
break
}
fmt.Println(v)
}
var a struct{}
exitChan <- a
}
func main() {
var ch chan int
ch = make(chan int, )
exitChan := make(chan struct{}, ) go send(ch, exitChan)
go recv(ch, exitChan)
var total =
for _ = range exitChan {
total++
if total == {
break
}
}
}
goroutine_sync2
检测管道是否关闭
package main import "fmt" func main() {
var ch chan int
ch = make(chan int, )
for i := ; i < ; i++ {
ch <- i
}
close(ch)
for {
var b int
b, ok := <-ch
//检测管道是否关闭
if ok == false {
fmt.Println("chan is close")
break
}
fmt.Println(b)
}
}
检测管道是否关闭
如何关闭chan
. 使用内置函数close进行关闭,chan关闭之后,for range遍历chan中
已经存在的元素后结束
. 使用内置函数close进行关闭,chan关闭之后,没有使用for range的写法
需要使用,v, ok := <- ch进行判断chan是否关闭
chan的只读和只写
只读的声明
Var 变量的名字 <-chan int
Var readChan <- chan int 只写的声明
Var 变量的名字 chan<- int
Var writeChan chan<- int
package main import "fmt" //只写chan
func send(ch chan<- int, exitChan chan struct{}) {
for i := ; i < ; i++ {
ch <- i
}
close(ch)
var a struct{}
exitChan <- a
} //只读chan
func recv(ch <-chan int, exitChan chan struct{}) {
for {
v, ok := <-ch
if !ok {
break
}
fmt.Println(v)
}
var a struct{}
exitChan <- a
} func main() {
var ch chan int
ch = make(chan int, ) //初始化chan
exitChan := make(chan struct{}, ) go send(ch, exitChan)
go recv(ch, exitChan) var total =
for _ = range exitChan {
total++
if total == {
break
}
} }
只读只写示例chan
不阻塞
package main import "fmt"
import "time" func main() {
var ch chan int
ch = make(chan int, )
ch2 := make(chan int, )
go func() {
var i int
for {
ch <- i
time.Sleep(time.Second)
ch2 <- i * i
time.Sleep(time.Second)
i++
}
}()
for {
select {
case v := <-ch:
fmt.Println(v)
case v := <-ch2:
fmt.Println(v)
case <-time.After(time.Second):
fmt.Println("get data timeout")
time.Sleep(time.Second)
}
}
}
chan不阻塞
Golang之并发篇的更多相关文章
- golang的并发
Golang的并发涉及二个概念: goroutine channel goroutine由关键字go创建. channel由关键字chan定义 channel的理解稍难点, 最简单地, 你把它当成Un ...
- golang的并发不等于并行
先 看下面一道面试题: func main() { runtime.GOMAXPROCS(1) wg := sync.WaitGroup{} wg.Add(20) for i := 0; i < ...
- go---weichart个人对Golang中并发理解
个人觉得goroutine是Go并行设计的核心,goroutine是协程,但比线程占用更少.golang对并发的处理采用了协程的技术.golang的goroutine就是协程的实现. 十几个gorou ...
- golang实现并发爬虫三(用队列调度器实现)
欲看此文,必先可先看: golang实现并发爬虫一(单任务版本爬虫功能) gollang实现并发爬虫二(简单调度器) 上文中的用简单的调度器实现了并发爬虫. 并且,也提到了这种并发爬虫的实现可以提高爬 ...
- Java并发篇
Java并发篇 作者:星晴(当地小有名气,小到只有自己知道的杰伦粉) 1. Java锁 1.1 乐观锁 1.2 悲观锁 1.3 自旋锁 1.4 Synchronized 同步锁 1.4.1 核心组件 ...
- 多线程JUC并发篇常见面试详解
@ 目录 1.JUC 简介 2.线程和进程 3.并非与并行 4.线程的状态 5.wait/sleep的区别 6.Lock 锁(重点) 1.Lock锁 2.公平非公平: 3.ReentrantLock ...
- Golang学习-第二篇 搭建一个简单的Go Web服务器
序言 由于本人一直从事Web服务器端的程序开发,所以在学习Golang也想从Web这里开始学起,如果对Golang还不太清楚怎么搭建环境的朋友们可以参考我的上一篇文章 Golang的简单介绍及Wind ...
- Golang学习-第一篇 Golang的简单介绍及Windows环境下安装、部署
序言 这是本人博客园第一篇文章,写的不到位之处,希望各位看客们谅解. 本人一直从事.NET的开发工作,最近在学习Golang,所以想着之前学习的过程中都没怎么好好的将学习过程记录下来.深感惋惜! 现在 ...
- 说说Golang goroutine并发那些事儿
摘要:今天我们一起盘点一下Golang并发那些事儿. Golang.Golang.Golang 真的够浪,今天我们一起盘点一下Golang并发那些事儿,准确来说是goroutine,关于多线程并发,咱 ...
随机推荐
- mysql 笔记分享
mysql LPAD 和RPAD不足位数补齐填充函数总结一下mysql数据库的一些特征MySQL WHERE 语句优化之我见mysql limit 实例详解mysql 如何实现多表联合更新MySQL ...
- Linux火焰图-centos
centos7.5mini安装 yum install -y yum-utils perf debuginfo-install -y perf #debuginfo-install下载了305MB的文 ...
- express基础
express框架 const express = require("express"); 引入express框架 var app= express(); 实例化 相当于构造函 ...
- Java集合类性能分析
[转]对于Android开发者来说深入了解Java的集合类很有必要主要是从Collection和Map接口衍生出来的,目前主要提供了List.Set和Map这三大类的集合,今天Android吧(ard ...
- IP分组交付和转发
1:交付 网络层监视底层物理网络对分组的处理过程叫做交付,分为直接交付和间接交付 1.1:直接交付 直接交付时,分组的终点是一台与交付着连接在同一个网络上的主机,发生在俩种情况下,分组的源点和终点都在 ...
- java8函数式编程(转载)
1. 概述 1.1 函数式编程简介 我们最常用的面向对象编程(Java)属于命令式编程(Imperative Programming)这种编程范式.常见的编程范式还有逻辑式编程(Logic Progr ...
- Dark theme for Texstudio - TeX - LaTeX
Dark theme for Texstudio ~~~ 1.window系统如下操作 ~~~ 1. texstudio的配置文件texstudio 的配置文件在~/.config/texstudi ...
- MacBook Pro 一月使用体验
从 2013 年开始,就特别想买 MBP,终于在 2015 年的尾巴用上了 MBPR.原本是要在使用一周后写一份使用体验的,但因为懒,现在拖到一个月了,刚好现在也是2016年的一月,就把标题改成一月使 ...
- springboot实现国际化
1.编写配置文件 2.在application.properties中添加 i18n指的是国际化所在包名 3.实现国际化的接口 4.在配置类中
- IdUDPServer中文汉字乱码 及IdTCPClient
官网 http://www.indyproject.org/docsite/html/frames.html?frmname=topic&frmfile=TIdTCPServer_OnExec ...