Go语言实现异步
同步与异步
同步异步 , 举个例子来说,一家餐厅吧来了5个客人,同步的意思就是说,来第一个点菜,点了个鱼,好, 厨师去捉鱼杀鱼,过了半小时鱼好了给第一位客人,开始下位一位客人,就这样一个一个来,按顺序来
相同, 异步呢,异步的意思就是来第一位客人,点什么,点鱼,给它一个牌子,让他去一边等吧,下一位客人接着点菜,点完接着点让厨师做去吧,哪个的菜先好就先端出来,
同步的优点是:同步是按照顺序一个一个来,不会乱掉,更不会出现上面代码没有执行完就执行下面的代码, 缺点:是解析的速度没有异步的快;
异步的优点是:异步是接取一个任务,直接给后台,在接下一个任务,一直一直这样,谁的先读取完先执行谁的, 缺点:没有顺序 ,谁先读取完先执行谁的 ,会出现上面的代码还没出来下面的就已经出来了,会报错;
(以上摘自知乎)
在go语言中使用goroutine其实很容易区分是否为异步,当调用方的 goroutine 和方法执行的 goroutine 不是同一个 goroutine,那么就可以说是异步的。如果是同一个则为同步。
阻塞和非阻塞的区别
阻塞和非阻塞的最大区别在于——是否等待结果,而且在非阻塞里面,主动询问结果和被动接收结果(技术上也称回调机制)是两种不同的获取结果的方式。另外,我们也可以看到,异步可以是阻塞的也可以是非阻塞的,但是同步一般不会说阻不阻塞,因为等蛋糕的人(你) 和做蛋糕的人(你) 是同一个人(产出结果的就是执行方)。
选择阻塞还是非阻塞呢?
阻塞的方式处理结果的地方是原本的 goroutine,而不像非阻塞的回调函数,执行在另外一个 goroutine 上,这一点让非阻塞的方式看起来更加地异步,但是更加异步就意味着更少控制,因为我们的主流程始终是原本的 goroutine,所以非阻塞的方式会让结果的处理逻辑看起来不那么重要,而阻塞的方式由于结果还是交给主流程的 goroutine 去处理,所以会显得更重要。
换句话说,阻塞之所以是阻塞,不就是因为我们需要拿到结果所以才等待的吗?只不过在等待结果产出的时候我们希望可以先去做别的事,不用傻傻地等着,而非阻塞相当于把结果都交给了别人处理,这种方式对结果的重视程度可想而知。于是,我们得出了一个结论:结果重要的时候,选择阻塞的方式;结果不太重要的时候,选择非阻塞的方式。
go实现阻塞异步
package main
import "fmt"
func main() {
// 方法的两个参数
a := 1
b := 2
// 从管道中接收结果,这一步是阻塞的,因为在等待结果的产出
sum := <-addAsync(a, b)
fmt.Println(sum)
}
func addAsync(a int, b int) chan int {
// 使用管道接收结果,注意需要设置一个缓冲位,否则没有取结果的话这个 goroutine 会被阻塞
resultChan := make(chan int, 1)
go func() {
// 在新的 goroutine 中计算结果,并将结果发送到管道
resultChan <- a + b
}()
return resultChan
}
go语言实现非阻塞异步
package main
import (
"fmt"
"time"
)
func main() {
// 方法的两个参数
a := 1
b := 2
// 调用方法的时候加上回调函数
// 这个回调函数会在得到结果之后执行
addWithCallback(a, b, func(sum int) {
fmt.Println(sum)
})
// 防止 main goroutine 比异步任务的 goroutine 先退出
time.Sleep(time.Second)
}
func addWithCallback(a int, b int, callback func(sum int)) {
go func() {
// 在新的 goroutine 中计算结果,并将结果传递给回调函数
sum := a + b
callback(sum)
}()
}
转载自:https://juejin.cn/post/7041533985490468901