最近在使用golang做一个爬虫,涉及到多线程,golang是没有多线程的,但是有一种更轻量级能达到类似多线程的效果,协程,golang原生支持协程。
一、怎么理解协程?
协程是golang语言特性的实现,比线程更低一级的运行方式,它不属于操作系统功能,不由操作系统分配cpu、内存,而是由golang自己实现运行资源的调度使用。也正是因此执行效率要高于线程。但是协程需要主动让出控制权后供其他协程运行。
二、如何创建协程?
这里有2种方式创建:
1、使用go创建
go sf("a")
2、使用go函数块创建
go func() {
sf("b")
}()
三、使用协程的问题
1、主线程执行完成后直接结束了,此时若协程未执行完成,也会直接结束,毫无征兆。
下面是个例子
func main() {
fmt.Println("开始启动...")
go sf("a")
go sf("b")
}
func sf(s string) {
for i := 0; i < 10; i++ {
fmt.Println(s+" ->>>", i)
}
}
运行完成之后根本不会等两个协程完成运行,主函数直接结束了,如果将代码改一下
改版1:
func main() {
fmt.Println("开始启动...")
go sf("a")
go sf("b")
time.Sleep(time.Duration(2)*time.Minute)
}
在主函数这里阻塞一下,就可以了,但是这种方式在实际开发中是不可行的,大多不能提前知道协程需要多久运行完成。
改版2:
func main() {
fmt.Println("开始启动...")
var wg = sync.WaitGroup{}
wg.Add(2)
go func() {
sf("a")
wg.Done()
}()
go func() {
sf("b")
wg.Done()
}()
wg.Wait()
}
这样运行就ok了,这里使用了golang的WaitGroup。
理解起来就是创建一个等待的组,可以动态的添加组员的数量,然后在主函数最后一行执行wg.Wait() 来阻塞检查组员是否都完成了,协程中调用wg.Done()方法进行减一操作告知当前协程完成。
这样也会带来新的问题:
1、无法精确控制协程
2、无法准确得知哪个协程完成了或未完成
3、代码过于原始(繁琐)
拿java的多线程来理解,这个WaitGroup就像一个线程池,但是池子里只有计数器,没有实际对象。在Wait()方法一直在等待WaitGroup的校验信号,当一个协程完成时使用Done()通知WaitGroup已完成,当所有协程全部通知完成了Wait()释放,这就是一个非常简单的消息模型。
在协程这块,希望golang能优化使用方式,尽可能优雅一些。
找到了一篇讲的挺到位的文章,手动传送门 https://www.cnblogs.com/liang1101/p/7285955.html
有疑问加站长微信联系(非本文作者)