go语言
并发
并行
信道
package main import ( "fmt" "time" ) 补充: //并发:看上去在同一时间同时执行,实际是切换执行利用时间片轮转法,同一个CPU进行切换执行 // 并行:是在真正的同一时间两个程序同时进行吗,这个是在多核cpu情况下,同一时刻,两个事情同时进行 //进程:进程是程序执行的最小单位,例如qq进程,迅雷进程, // 线程: 例如迅雷进程中,有上传,下载,上传就是一个线程,下载就是另一个线程 // 协程:当线程碰到io操作时,就会一直停在那里,这个线程就一直处于浪费状态,此时我可以让这个线程转而去做其他的事, // 此时,就不是操作系统控制,而是由程序去控制,所以有genevt这个第三方模块,自动实现io切换,这就是单线程下实现并发即协程 // node.js 本身只能在游览器中去执行,于是写了一个引擎,让代码跑在这个引擎上(类似于解释器)就可以跑在服务端上 // 虽然js是一个解释型语言,但是node.js 使用了一个事件驱动,非阻塞i/o模型,运行特别快,碰到io就切 // python 的async/await 协程 http请求用asyncio 异步框架sanic // python 中要想速度高,就得使用异步编程,异步框架 //go中用关键字go即可,go语言并发性能高,go协程 // go协程原理:go语言一旦跑起来,会在内部建一个很大的线程池,在线程池中go自己写好了算法,自己去调度,遇到io自己去切,自己去执行任务 func test() { fmt.Println("hello go") } //协程之间如何进行数据通信,就用信道 func main() { //本质是goroutine 当新开的线程没结束,主线程已经结束了,所以要想打印,就得等待一会 go test() go test() go test() go test() go test() //是开了好多,速度很快 time.Sleep(time.Second*2)//Second表示秒 ,此时表示睡2秒 }
信道
也叫管道,通道,go是csp管道模型进行通信
package main import ( "fmt" ) //信道 //信道也是一个变量,信道运输的类型必须固定 // 重点:信道的放值和取值在默认情况下都是阻塞的 // 单向信道,即只能放或者只能取 // 关闭信道,信道关闭后就不能再放取值了 close(信道名),用rang func test1(c chan bool) { fmt.Println("hello go") //一旦执行完了,在信道中放入一个值 ***********++++++++++ c <-true //向信道中放值 } func main() { //定义一个信道,关键字chan 后面跟信道类型 //信道的空值是 nil 引用类型 //var a chan int //表示定义了一个int类型的信道,该信道只能运输int类型的数据 //fmt.Println(a) //信道定义并初始化 var a chan int =make(chan int) fmt.Println(a) //重点:放值和取值 //箭头向信道变量,就是往信道中放值 a <-1 //箭头向外,表示从信道中取值 <-a 表示从信道取出来的值不要了(没赋值给变量) var b int= <-a fmt.Println(b) //信道默认情况下,取值和赋值都是阻塞的,就是一旦向信道中放入一个值,程序就卡在这里,不会继续向下执行, //此时必须另一个协程把它取走,程序才会继续执行,如果这个协程取,里面没有值,这个协程也会卡在这里 //定义一个信道 var c chan bool=make(chan bool) //必须初始化 go test1(c) //从信道中取出值,***********++++++++++ d:=<-c fmt.Println(d) //time.Sleep(time.Second*2) }
用rang循环,
3,缓冲信道
信道的本质是刚开始信道里并没有放值,所以才会阻塞,此时放是放不进去的,只有有另一个去取的时候,两者一对接,把值给它了
缓冲信道,有缓冲大小
package main import "fmt" func main() { // 缓冲信道 //定义一个缓冲大小为3的信道 var a chan int = make(chan int,3) a <-1 a <-2 a <-3 //a <-4 //缓冲大小为3,只能放3个,此时超了,就会阻塞,但是程序不会一直处于阻塞,此时就报死锁错误 <-a <-a //取值 b:=<-a fmt.Println("xxx") fmt.Println(b) //3 如果再取就会报死锁错误 }
缓冲信道例子(协程的利用)