最近爬取一个网站的数据,但是速度太慢了,所以想要利用多线程或者多进程的方式来爬取代码。
前言
翻阅了一下网上的资料,发现很多人对python多线程嗤之以鼻, 详情请点击这里 大概是说python的多线程不是真正意义上的多线程!因为python的解释器Cpython有一个叫做 **Global Interpreter Lock(全局解释器锁)**的东西,由于GIL锁存在,python里一个进程永远只能同时执行一个线程(拿到GIL的线程才能执行)。
-
多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理(Chip-level multithreading)或同时多线程(Simultaneous multithreading)处理器。 来源于维基百科
-
CPython 是用C语言实现的 Python 解释器。 作为官方实现,它是最广泛使用的 Python 解释器。
但是,python 的多线程并没有你想象的这么差,还有些大佬也提出了自己的看法,表示需要具体问题具体分析。
代码实现
多进程实现
# -*- coding:utf-8 -*-
"""
Process常用属性与方法:
name:进程名
pid:进程id
run(),自定义子类时覆写
start(),开启进程
join(timeout=None),阻塞进程
terminate(),终止进程
is_alive(),判断进程是否存活
"""
from multiprocessing import Process
import os, time, random
def processfun(msg):
t_start = time.time()
print("%s开始执行,进程号为%d" % (msg,os.getpid()))
time.sleep(random.random()*2)
t_stop = time.time()
print(msg,"执行完毕,耗时%0.2f" % (t_stop-t_start))
def main():
print("主进程执行中>>> pid={0}".format(os.getpid()))
ps = []
# 创建子进程实例
for i in range(2):
p = Process(target=processfun, name="worker" + str(i), args=(str(i)))
ps.append(p)
# 开启进程
for i in range(2):
ps[i].start()
# 阻塞进程
for i in range(2):
ps[i].join()
print("主进程终止")
if __name__ == '__main__':
main()
进程池实现
from multiprocessing import Pool
import os, time, random
def processfun(msg):
t_start = time.time()
print("%s开始执行,进程号为%d" % (msg,os.getpid()))
time.sleep(random.random()*2)
t_stop = time.time()
print(msg,"执行完毕,耗时%0.2f" % (t_stop-t_start))
if __name__ == '__main__':
po = Pool(3) # 定义一个进程池,最大进程数3
for i in range(0,10):
po.apply_async(processfun,(i,)) # Pool().apply_async(要调用的目标,(传递给目标的参数元祖,))
po.close() # 关闭进程池,关闭后po不再接收新的请求
po.join() # 等待po中所有子进程执行完成,再执行下面的代码,可以设置超时时间join(timeout=)
进程锁:
lock = multiprocessing.Lock() # 创建一个锁
lock.acquire() # 获取锁
lock.release() # 释放锁
with lock: # 自动帮你获取和释放锁
进程池的进程锁
from multiprocessing import Pool, Manager
lock = Manager().Lock() # 创建锁的方式不一样 其他都一样
进程间传递信息
mylist = multiprocessing.Manager().list(range(5)) # 主进程与子进程共享这个List