并发
协程
使用go
关键字后面跟着函数调用, 可以将这个函数的执行过程放在另一个协程(新手可以粗暴理解为新的进程)
go func(){
sleep(3); // 等待3秒
print("Inside!");
}()
print("Outside")
多协程并发任务
如果你有一系列的任务, 并且任务的参数都放在了一个数组内, 那么数组的asyncMap
方法可以帮你并发地执行这些任务
var start = now();
var res = [1, 2, 3, 4].asyncMap(e => {
sleep(3); // 假如计算e*e是一个需要耗时3秒的行为
return e * e;
}, 4); // 4个并发
print(fmt.Sprintf("Cost time %v, Result: %v", now().Sub(start), res));
将上例的.asyncMap
替换成.map
即可测试无并发的情况
并发锁
并发map
可参考map, 如
// 并发安全
m = new(sync.Map)
代码块
通过以下方法可以保证并发场景下全局仅有count个协程执行代码内容, count缺省为1
synchronized(lock, [count]) {
// 代码内容
}
其中lock参数可以为string类型(推荐)
或其它可序列化的对象
通道
声明
可以通过以下语句声明一个通道
c = new('chan') // 声明一个不限定类型的通道
c = new('chan', 0) // 声明一个指定类型的通道, 第二个参数用于获取参数
c = new('chan', 0, 1) // 第三个参数用于指定缓冲区的大小
c = new('chan', 0, 1, 'w') // 第四个参数指定了通道是否只读、只写
读取数据
从通道读取数据:
<- c // 阻塞到通道获取到值
rec = (<- c) // 读取并赋值
rec <- c // 从读取值声明一个当前作用域的变量
chanrecv(c) // 阻塞读取
chanrecv(c, true) // 不阻塞(尝试)读取
chanrecv(c, c1, c2...) // 从多个通道读取最先有值传递的
chanrecv(c, c1, 3...) // 传入int或float时, 表示设置读取超时时间
值得一提的是, 以上所有<-
都可以换成->
, 然后将两边调换即可
写入数据
将数据写入通道:
c <- "hahaha" // 将一个字符串写入通道
"heiheihei" -> c // 同样的效果
chansend(c, 123) // 使用方法写入, 尤其在chan chan xxx类型时必须使用该方法
示例
c = new('chan')
go func(){
var s = now()
print("Start listen from chan")
rec <- c
printf('Chan get %v after %v', rec, now().Sub(s))
}()
print("Ready to send")
sleep(3)
"zwr" -> c
print("Send over")
PS: 当使用<-
或->
时, 为了区分是读取还是写入操作, 要求双方不能同时为chan类型. 如果双方都是chan类型时[例如 new('chan', new('chan'))声明的用于传输通道的通道] 需要调用chanrecv
或chansend
方法以显式指定操作