最近学习使用go来做一个简单的爬虫,代码中用到了多线程,就想趁机会记录一下学习感想。
场景是:在从文件中读取到多少个基金号就开启多少个线程去获取相关基金的数据,并且在所有基金信息(线程)获取完成后进行存储和筛选。
目测需要用到的技术有,互斥锁,线程同步
Go和python的锁
在Go中, 锁和解锁
首先,在多线程中,每一个基金爬取后的数据都需要写入一个切片,那我们不希望线程可以同时访问这个切片,所以再写入资源的时候需要加锁。
var mutex sync.Mutex mutex.Lock() // 更新切片 mutex.Unlock()
在第一次被使用后,不能再对sync.Mutex进行复制。
在python中,请求锁和释放锁,其实差不多。
from threading import Lock lock = Lock() lock.acquire() # 更新数据 lock.release()
锁的类型不只有互斥锁,go中有RWMutex读写互斥锁,我还没有接触过,不好做解释,python中有RLock锁是对Lock做了优化。python还有GIL全局锁的概念,如果根据这个概念,那在python中lock.acquire()请求锁,和lock.release()释放锁的命名就说到通了,有点意思。
Go的线程同步
再聊聊go的线程同步,线程同步不是必须的,还是需要根据场景来看的,如果我们需要所有的数据产生后,统一处理的话,线程同步是有必要的。
在go中,sync.WaitGroup
wg = sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func() { // Get fund info wg.Done() }() } wg.Wait
sync.WaitGroup有一个计数器,有点像python回收机制的引用记数,当计数器为0,wait就会返回,否则就会一直阻塞goroutine直到计数器归零。通过使用Done()来让计数器减一。
python的线程同步我还没用过,这里就不好讨论了。