最近写微博爬虫的时候,发现爬的实在是太慢了,昨天看到王老师拿多个微博的cookie去开多个线程爬微博的点赞的列表,于是就决定看一下多线程的知识。之前学习Java的时候也没有好好学习多线程的知识,也算是补偿一点小遗憾吧
我们前面编写的所有的Python程序,都是执行单任务的进程,也就是只有一个线程。如果我们要同时执行多个任务怎么办?
有两种解决方案:一种是启动多个进程,每个进程虽然只有一个线程,但多个进程可以一块执行多个任务。
还有一种方法是启动一个进程,在一个进程内启动多个线程,这样,多个线程也可以一块执行多个任务。
当然还有第三种方法,就是启动多个进程,每个进程再启动多个线程,这样同时执行的任务就更多了,当然这种模型更复杂,实际很少采用。
总结一下就是,多任务的实现有3种方式。
多进程模式;
多线程模式;
多进程+多线程模式。
Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。
import os
print('Process (%s) start...' % os.getpid())
# Only works on Unix/Linux/Mac:
pid = os.fork()
if pid == 0:
print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
else:
print('I (%s) just created a child process (%s).' % (os.getpid(), pid))
一开始不理解,后来发现,正因为fork()的特殊性。一次调用会返回两个值,所以在执行的时候就会出现以下的结果了
不是一个很喜欢记录知识点的人,emmm多线程更多的知识点可以看廖雪峰的网站这里只记录一些自己有感触的点
多线程在python中其实是一个伪命题,启动与CPU核心数量相同的N个死循环的线程,在4核CPU上可以监控到CPU占用率仅有102%,也就是仅使用了一核。但是用C、C++或Java来改写相同的死循环,直接可以把全部核心跑满,4核就跑到400%,8核就跑到800%,为什么Python不行呢?
因为Python的线程虽然是真正的线程,但解释器执行代码时,有一个GIL锁:Global Interpreter Lock,任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。
所以,在python中,可以使用多线程,但不要指望通过多线程有效利用多核。
Python虽然不能利用多线程实现多核任务,但可以通过多进程实现多核任务。多个Python进程有各自独立的GIL锁,互不影响。
最后在自己的爬虫中选择用了进程池创建了许多的进程,发现爬虫的运行效率得到了显著的提升。