Go语言并发编程入门教程第五节是什么内容?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1551个文字,预计阅读时间需要7分钟。
在前面,由于并发相关的技术越来越多、越来越复杂,这个专题会分成多篇文章来详细探讨。本篇内容包括:
+ 携程机制+ 携程与线程的区别+ 使用锁来控制并发+ 使用通道(channel)来控制并发
写在前面
因为并发相关的东西又多又长。。所以这个专题会分成多篇博客来写啦。。 本篇文章包括
- 携程机制,携程和线程的区别
- 使用锁来控制并发
- 使用通道(channel)来控制并发
- 通道的多路控制和超时(select语句块)
Go语言的并发操作(一)
1. Go语言的携程机制
- 线程和携程的区别(携程是更加轻量级的线程)
- JDK5之后一个线程的默认栈道大小是5M,而携程栈的大小是2K
- Java中线程和系统线程的对应关系是1:1,但是携程是n:m
线程由于涉及到处理器切换人物,会导致吞吐率下降。而使用携程,可以做到多个携程只会使用一个系统现场。利用这种方式降低切换线程上下文的成本
- 携程的简单使用携程的使用非常简单,在需要运行的函数前面加上go关键字就可以了个人认为只需要把携程看成轻量级线程,使用时可以直接当成线程使用
上面的程序输出结果如下(由于处理机调用的时间不一致,所以并不会出现顺序的数字)
=== RUN TestGroutine 4 7 5 6 1 8 9 0 2 3 --- PASS: TestGroutine (0.10s) PASS
2. Go 语言的共享内存并发机制
- 使用锁来控制多线程程序先看一个在没有锁的情况下使用携程(多线程)把一个值累加点结果
结果如下,可以看见我们丢失了正确的鞋操作
counter = 4799
为了获得正确的结果,我们需要使用锁,和等待队列
3. CSP的并发控制
CSP相当于是通过通道(发送消息)的机制来进行线程通讯。CSP的操作是通过一个Channel来完成的。也就是,这种方式会比使用直接通讯耦合度更低
- Channel的交互机制
- 主动式交互:如果消息消费者离线,那么消息生产者就会阻塞
- 队列(缓存)式交互:在消息队列未满之前,消息的生产者可以一直放入消息,如果消息队列满了,那么消息生产者就会阻塞
- CSP实现异步调用,延迟返回值
- 例如这里的Service方法是需要异步调用的
- 包装上面的方法,返回一个channel(注意代码里的chan类型的定义方式和把函数放入调用的方式)
- 这样调用asyncService方法的时候虽然可以很快的返回chan类型的数据,但是本质上任然是通过携程异步调用的,立即去获取chan里的值将会因为异步调用没有返回值而被阻塞我给出一个调用案例如下
结果如下
=== RUN TestTask 开始异步调用 do something else 异步调用结束 do something --- PASS: TestTask (1.01s) PASS
- 创建一个带消息容量的channel是需要再make方法的参数后面加上一个int来表示消息队列的容量就好了,如下
由于我对我的老本行——java后端的异步调用还不是很熟悉,那我就趁热打铁,写一个Demo实现Java的异步调用
这一部分是使用Java的Callable和FutureTask来完成异步调用,在获取调用结果的时候如果没有完成,主线程就会阻塞直到任务完成。如果不感兴趣可以直接跳到下一个大标题
- 使用Callable和ExecutorService线程池来完成任务
- 使用FutureTask的普通的Thread来完成任务
4. 多路选择和超时(select块的使用)
select块就是用于多个异步调用的多路选择和超时控制。
select语句块类似switch,每一个case里都要使用一个频道(chan类型)来获得数据。只要有一个channel返回了数据,那么这个channel的语句块就会执行。如果都没有返回值,有default语句块的话就会执行default语句块
这里的channel应该提前启动好,当我们要获取结果时再去做相关处理
func TestSelect1(t *testing.T) { s := asyncService() time.Sleep(time.Millisecond*1000) select { //这一个语句块是为了做超时处理,10s后如果没有结果他就会返回结果 //(当然有了default语句块这个语句块也就没有意义了) case <-time.After(10*time.Second): print("10s") case ret := <-s: print("result:",ret) default: t.Error("error") }}本文共计1551个文字,预计阅读时间需要7分钟。
在前面,由于并发相关的技术越来越多、越来越复杂,这个专题会分成多篇文章来详细探讨。本篇内容包括:
+ 携程机制+ 携程与线程的区别+ 使用锁来控制并发+ 使用通道(channel)来控制并发
写在前面
因为并发相关的东西又多又长。。所以这个专题会分成多篇博客来写啦。。 本篇文章包括
- 携程机制,携程和线程的区别
- 使用锁来控制并发
- 使用通道(channel)来控制并发
- 通道的多路控制和超时(select语句块)
Go语言的并发操作(一)
1. Go语言的携程机制
- 线程和携程的区别(携程是更加轻量级的线程)
- JDK5之后一个线程的默认栈道大小是5M,而携程栈的大小是2K
- Java中线程和系统线程的对应关系是1:1,但是携程是n:m
线程由于涉及到处理器切换人物,会导致吞吐率下降。而使用携程,可以做到多个携程只会使用一个系统现场。利用这种方式降低切换线程上下文的成本
- 携程的简单使用携程的使用非常简单,在需要运行的函数前面加上go关键字就可以了个人认为只需要把携程看成轻量级线程,使用时可以直接当成线程使用
上面的程序输出结果如下(由于处理机调用的时间不一致,所以并不会出现顺序的数字)
=== RUN TestGroutine 4 7 5 6 1 8 9 0 2 3 --- PASS: TestGroutine (0.10s) PASS
2. Go 语言的共享内存并发机制
- 使用锁来控制多线程程序先看一个在没有锁的情况下使用携程(多线程)把一个值累加点结果
结果如下,可以看见我们丢失了正确的鞋操作
counter = 4799
为了获得正确的结果,我们需要使用锁,和等待队列
3. CSP的并发控制
CSP相当于是通过通道(发送消息)的机制来进行线程通讯。CSP的操作是通过一个Channel来完成的。也就是,这种方式会比使用直接通讯耦合度更低
- Channel的交互机制
- 主动式交互:如果消息消费者离线,那么消息生产者就会阻塞
- 队列(缓存)式交互:在消息队列未满之前,消息的生产者可以一直放入消息,如果消息队列满了,那么消息生产者就会阻塞
- CSP实现异步调用,延迟返回值
- 例如这里的Service方法是需要异步调用的
- 包装上面的方法,返回一个channel(注意代码里的chan类型的定义方式和把函数放入调用的方式)
- 这样调用asyncService方法的时候虽然可以很快的返回chan类型的数据,但是本质上任然是通过携程异步调用的,立即去获取chan里的值将会因为异步调用没有返回值而被阻塞我给出一个调用案例如下
结果如下
=== RUN TestTask 开始异步调用 do something else 异步调用结束 do something --- PASS: TestTask (1.01s) PASS
- 创建一个带消息容量的channel是需要再make方法的参数后面加上一个int来表示消息队列的容量就好了,如下
由于我对我的老本行——java后端的异步调用还不是很熟悉,那我就趁热打铁,写一个Demo实现Java的异步调用
这一部分是使用Java的Callable和FutureTask来完成异步调用,在获取调用结果的时候如果没有完成,主线程就会阻塞直到任务完成。如果不感兴趣可以直接跳到下一个大标题
- 使用Callable和ExecutorService线程池来完成任务
- 使用FutureTask的普通的Thread来完成任务
4. 多路选择和超时(select块的使用)
select块就是用于多个异步调用的多路选择和超时控制。
select语句块类似switch,每一个case里都要使用一个频道(chan类型)来获得数据。只要有一个channel返回了数据,那么这个channel的语句块就会执行。如果都没有返回值,有default语句块的话就会执行default语句块
这里的channel应该提前启动好,当我们要获取结果时再去做相关处理
func TestSelect1(t *testing.T) { s := asyncService() time.Sleep(time.Millisecond*1000) select { //这一个语句块是为了做超时处理,10s后如果没有结果他就会返回结果 //(当然有了default语句块这个语句块也就没有意义了) case <-time.After(10*time.Second): print("10s") case ret := <-s: print("result:",ret) default: t.Error("error") }}
