在爬虫中的数据下载部分,由于单线程下载非常慢,这里要考虑使用多线程。
1. 进程
1) 在Unix/Linux操作系统里面,系统提供了Fork()调用,跟普通的函数不同,fork调用一次,返回两次。因为操作系统把当前进程(父进程)复制了一份(子进程),所以在父和子进程内分别返回,即返回两次。子进程返回0,父返回子进程的ID.
2) 在windows里面没有fork调用,但是python提供了multiprocessing模块来支持其跨平台性
3) 另外还有进程间通信等等 具体可以参见廖雪峰的网站
2. 线程
一个进程内的多个线程。线程是最小的执行单元。
一般使用threading这个高级模块。
启动一个线程,就是把一个函数传入,创建Thread实例,然后start()执行
运行结果:
可以看到:
首先程序进程运行起来之后,会启动主线程MainThread,current_thread()函数永远返回当前线程的实例,这时候输出第一行;
之后,子进程的名字在创建时指定,由 threading.Thread()创建
3. Lock
多线程之间共享数据,同时更改同一个变量,所以可能把内容搞混乱。
看下面的例子:
这里有两个线程t1和t2,同时都在操作balance,而操作balance需要多个语句,很可能在操作过程中被另外一个线程打断。最终导致结果出错。
所以说,需要加线程锁。
锁的作用就是说在某个线程开始执行change_it时候,因为该线程获得了锁,其他的线程不能同时执行change_it()。不论多少个线程,锁只有一个,所以在某个特定的时刻,执行change_it()的只能是某个特定的线程。
这样就可以保护到变量了。
4. 分布式进程
在多线程和多进程上来看,优先选择多进程,因为process更稳定,而且可以分配到多台机器上去。
python中的multiprocessing 模块支持多进程。其中的manager 子模块还支持把多进程分布到多个机器上。一个服务进程作为调度者,将任务分布到其他多个进程中去,依靠网络进行通信。
参见廖雪峰分布式进程
5. 协程
协程是单个线程执行的。
优势:
1)由于不用线程之间的切换(线程数多时候消耗大),所以与多线程比起来,协程的执行效率非常高。
2) 不需要线程锁。
要利用多核CPU,一般用多进程+协程。 ( 所以看来多线程还是用的比较少的)
在python中,我们一般用第三方库 gevent 来支持协程。gevent用到的主要模式是greenlet.
下面看一下运行结果,可以看到,三个函数是并发执行的,但是只有一个线程。
需要注意的是,gevent 在 unix和Linux下都可以高并发的地执行,但是在windows下可能会有报错。
看一下,我们的爬虫代码里面的Gevent实例
先加入库,
然后在下载图片的地方,看到gevent.spawn(函数名,参数) 把函数变成gevent实例,最后加入实例池即可并行执行。