sync.Once: 只执行一次的代码,特别适合用于实现单例模式
go语言:sync.Once的用法
golang sync.Once 应用
Go语言——sync.Once分析
使用两个channel(长度为1)和两个goroutine,分别是oddChannel/oddGoroutine和evenChannel和evenGoroutine;
oddGoroutine在从oddChannel接收到数据1后开始打印奇数;打印完毕后,向evenChannel写入数据1,通知evenGoroutine开始打印偶数;
evenGoroutine在从evenChannel接收到数据1后开始打印偶数;打印完毕后,向oddChannel写入数据1,通知oddGoroutine开始打印奇数;
为使奇数开始先打印,还需要一个startChannel,该channel从main goroutine接收数据1,在startChannel收到数据1后开始奇数的打印,奇数打印完后开始偶数的打印;
所有线程执行结束后,需要关闭各goroutine,子goroutine的管理使用sync.WaitGroup进行;
参考代码: print_odd_even_test.go Test_Print_Odd_Even_Interview_Exec
第一次用 Golang 出面试题小记
使用两个channel(长度为1)和两个goroutine,分别是numChan/numGoroutine和letterChan/letterGoroutine;
numGoroutine在从numChan接收到数据1后开始打印数字;打印完毕后,向letterChan写入数据1,通知letterGoroutine开始打印字母;
letterGoroutine在从letterChan接收到数据1后开始打印字母;打印完毕后,向numChan写入数据1,通知numGoroutine开始打印数字;
为使数字开始先打印,还需要一个startChannel,该channel从main goroutine接收数据1,在startChannel收到数据1后开始数字的打印,数字打印完后开始字母的打印;
所有线程执行结束后,需要关闭各goroutine,子goroutine的管理使用sync.WaitGroup进行;
参考代码: interview_pipeline_print_num_letter_test.go
Gopher面试中的Coding 交替打印数字和字母
有四个线程1、2、3、4。线程1的功能就是输出1,线程2的功能就是输出2,以此类推…现在有四个文件ABCD。初始都为空。现要让四个文件呈如下格式:
A:1 2 3 4 1 2…
B:2 3 4 1 2 3…
C:3 4 1 2 3 4…
D:4 1 2 3 4 1…
参考代码: pipeline_print_to_file_test.go
测试时记得先创建好a.txt、b.txt、c.txt、d.txt文件
go 面试题
参考代码: factorial_test.go: TestFactorialWithMap
参考代码:factorial_test.go: TestFactorialWithConcurrentMap
参考代码:factorial_test.go: TestFactorialWithConcurrentMapAndChannel
intChan:存放输入数据的管道
primeChan:存放输出结果的管道
开启一个协程,专门负责向intChan中放入数据;
开启四个协程,专门负责从intChan中取出各个数据,并判断是否为素数,若是,则放入primeChan
参考代码: prime_test.go
尚硅谷_韩顺平_Go语言核心编程:16.8.6 应用实例3
参考代码:read_write_channel_test.go
尚硅谷_韩顺平_Go语言核心编程:16.8.6 应用实例1
square_test.go Test_Square_Infinity
square_test.go Test_Square_Limit
func main() {
runtime.GOMAXPROCS(1)
int_chan := make(chan int, 1)
string_chan := make(chan string, 1)
int_chan <- 1
string_chan <- "hello"
select {
case value := <-int_chan:
fmt.Println(value)
case value := <-string_chan:
panic(value)
}
}
本题考察goroutine的select操作,代码本身没有问题,可以正常编译通过并执行。
但是,在select时,当case value := <-string_chan先满足条件可以执行,或者case value := <-int_chan和case value := <-string_chan两者都满足条件但在随机选择时选中case value := <-string_chan分支时,会触发panic()语句的执行,从而触发异常
Go面试题答案与解析 5、下面代码会触发异常吗?请详细说明
进程是操作系统层面支持的并发模型,同是也是开销最大的一种并发模型。进程是系统进行资源分配的最小单位。
线程也是操作系统层面支持的并发模型,开销比进程小,并且线程依赖于进程而存在。线程是系统调度的最小单位。
协程,也被成为轻量级线程,依托于线程而存在,开销比线程更小,同时能创建比进程和线程更多的数量。目前支持协程的语言包括:Golang、Python、Erlang
简单理解为基于事件的调度模型,在发生事件时,执行相应回调函数。目前在Node.js中有很好的实践。
并发,说到底难点在于对共享变量访问控制,通常有以下两种实现模式:
基于锁机制,线程在操作共享变量时,通过对共享变量加锁,实现对共享变量的独占式使用;在使用完毕后释放锁,以便其他线程使用
基于消息机制,线程在收到消息后开始操作共享变量,并在操作完毕后传出消息,通知其他线程对共享变量进行操作
concurrent_control_mode_test.go Test_Concurrent_Control_Mode_By_Channel
concurrent_control_mode_test.go Test_Concurrent_Control_Mode_By_WaitGroup
concurrent_control_mode_test.go Test_Concurrent_Control_Mode_By_Context
Golang中的协程为一种轻量级的线程,这些协程的执行最终还是依赖于操作系统内核线程的执行。Golang中goroutine的调度器主要有4个重要组成部分,分别是G、P、M、Sched:
每次调用go关键字创建一个goroutine时,相当于向内核中提交了一个任务,这些任务的调度执行遵循如下流程(GPM调度模式可理解为线程池的调度模式):
G是顺序执行的是不是有点奇怪,跟我们实际了解到的情况不一样。原因是,启动的时候,会专门创建一个线程sysmon,用来监控和管理,在内部是一个循环:
Go全栈面试题(2) -Go进阶面试题
Go全栈面试题(2) -Go进阶面试题 互斥锁,读写锁,死锁问题是怎么解决。
Golang中的三种锁包括:互斥锁,读写锁,sync.Map安全的锁
Go全栈面试题(2) -Go进阶面试题 说下Go中的锁有哪些?
go_func_parameter_test.go
在第一个()处作传入参数类型声明,在第二个()处出入实际参数
channel_loop_test.go TestChannelLoop_1_AfterClose
在不明确知道channel长度时, 需要线先进行channel的关闭, 然后才能进行channel的遍历
channel_loop_test.go TestChannelLoop_2_BeforeClose
在明确知道channel长度时, 可以先使用普通的for循环进行channel的遍历, 在遍历后在进行channel的关闭
channel底层实现为一个队列,read & write可视为两个协程并发的操作这个队列
新建一个channel时,channel为空并且未关闭,readFlag=false & writeFlag=true,该channel等待goroutine写入数据;
当goroutine写入数据后,channel不为空并且未关闭,readFlag=true & writeFlag=false,该channel等待goroutine读取数据;
当goroutine读取完数据后,channel再次为空并且未关闭,readFlag=false & writeFlag = true, 等待goroutine写入数据;
如此,便实现两个goroutine对chan的读写操作
但是,当该channel为空并且未关闭时,readFlag=false & writeFlag=true,这个时候进行read操作便会因为并发修改channle而导致deadlock异常的出现
因此,在遍历channel之前,一定要确保channel已关闭,否则会出现deadlock问题
系统数据类型的默认值.
bool: false
int: 0
main goroutine在子goroutine还未执行完成时便退出, 导致子goroutine无法顺利执行
exit_main_test.go TestExitMain_Exception
例如如上测试案例: Goroutine 1和Goroutine 2很可能无法得到执行, 因为main goroutine退出会导致子goroutine没有时间执行
exit_main_test.go TestExitMain_1_WaitGroup
sync.WaitGroup内部实现了一个计数器,用来记录未完成的操作个数,它提供了三个方法:
Go并发:利用sync.WaitGroup实现协程同步
exit_main_test.go TestExitMain_2_Channel
exit_main_test.go TestExitMain_3_Sleep
Go全栈面试题(2) -Go进阶面试题 主协程如何等其余协程完再操作? & 如何等待所有goroutine的退出?
done := make(chan struct{})
done <- struct{}{}
go获取协程(goroutine)号