最近想用python写个爬虫,根据学校图书馆网站的学号来破解密码。由于学校图书馆初始密码为6位数字,而且不需要验证码,所以破解起来很简单。思路就是生成6为数字暴力密码本,依次向网页POST“学号-密码”的表单即可。然后问题来了,6位数字组成的密码,也就是0-9的六位全排列,共1000000中排列。 短短40行的单进程代码,需要56个小时才能把1000000个暴力密码轮询完毕。可怕。。。。 以前学习的时候,多线程和多进程的非阻塞式编程浅尝辄止,真是书到用时方恨少。
由于Python语言的“多线程”并不能提高效率,所以在这里温习一下“多进程”的用法:
python的用多进程池来管理所有的进程,步骤如下:
1)实例化进程池 p=Pool()。
2)通过apply_async()函数向进程池中添加进程。
3)通过p.close()函数关闭进程池,关闭之后无法继续添加新的进程。与此同时,CPU开始从进程池中取进程,若CPU有N核,则CPU每次只会取N个进程,待N个进程全部
执行完毕,再取出N个。直到将进程池中的进程取完为止。
4)通过p.join()函数等待所有进程被取出并执行完毕。
示例代码如下:
import time
from multiprocessing import Pool
def long_time_task(name):
print 'task %s starts running' % name
time.sleep(3)
print 'task %s ends running --3 seconds' % name
if __name__ =='__main__':
start = time.time()
p = Pool()
for i in range(4): # CPU有几核,每次就取出几个进程
p.apply_async(func=long_time_task, args=(i,))
p.close() # 调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了
p.join() # 对Pool对象调用join()方法会等待所有子进程执行完毕
end = time.time()
print('多进程(非阻塞)执行共需时间为:%.2f' % (end-start))
运行结果如下:
task 0 starts running
task 1 starts running
task 2 starts running
task 3 starts running
task 2 ends running --3 seconds
task 0 ends running --3 seconds
task 1 ends running --3 seconds
task 3 ends running --3 seconds
多进程(非阻塞)执行共需时间为:3.08
可以看出,我的CPU是4核,所以CPU每次取4个进程,同时执行,每个进程单独执行的时间是3秒(非阻塞式执行需要3*4=12秒),但同时执行后所用的实际时间为3.08秒。
然后我们把:
for i in range(4):
改成:
for i in range(5):
重新运行,结果如下:
task 0 starts running
task 1 starts running
task 2 starts running
task 3 starts running
task 0 ends running --3 seconds
task 4 starts running
task 1 ends running --3 seconds
task 2 ends running --3 seconds
task 3 ends running --3 seconds
task 4 ends running --3 seconds
多进程(非阻塞)执行共需时间为:6.08
可以看出增加了一个进程,总时间却增加了3秒。这是因为CPU先取出0-3号进程,执行完毕后,4号进程才开始执行。0-3号进程花了3秒钟,4号 进程也花了3秒。其实,如果我们添加8个进程,运行时间也是6秒左右。
-------------------------------------------------------------------------------------------------我是分割线-----------------------------------------------------------------------------------------------------------------------下面我们来研究一下apply_async()这个函数:
我们只用到两个参数func和args,前者传入函数名,后者传入参数值。
如果我们这样修改代码:把传入的函数名放在Tasks类中
import time
from multiprocessing import Pool
class Tasks():
def long_time_task(name):
print 'task %s starts running' % name
time.sleep(3)
print 'task %s ends running --3 seconds' % name
def long_time_task(name):
print 'task %s starts running' % name
time.sleep(3)
print 'task %s ends running --3 seconds' % name
if __name__ =='__main__':
task = Tasks()
start = time.time()
p = Pool()
for i in range(8): # CPU有几核,每次就取出几个进程
p.apply_async(func=task.long_time_task, args=(i,))
p.close() # 调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了
p.join() # 对Pool对象调用join()方法会等待所有子进程执行完毕
end = time.time()
print('多进程(非阻塞)执行共需时间为:%.2f' % (end-start))
print type(task.long_time_task)
print type(long_time_task)
我们运行之后,发现子进程并没有运行啊!! 这是怎么回事???我们先看下控制台:
多进程(非阻塞)执行共需时间为:0.14
<type 'instancemethod'>
<type 'function'>
可以看到 task.long_time_task的类型是‘instancemethod’(实例方法),而long_time_task的类型是'function'(函数),类型不一样,有可能是问题的根源哦。
然后继续修改程序,讲Tasks类中的long_time_task改成静态方法行不行呢?我们来试试看:
修改后的代码如下:
import time
from multiprocessing import Pool
class Tasks():
@staticmethod
def long_time_task(name):
print 'task %s starts running' % name
time.sleep(3)
print 'task %s ends running --3 seconds' % name
def long_time_task(name):
print 'task %s starts running' % name
time.sleep(3)
print 'task %s ends running --3 seconds' % name
if __name__ =='__main__':
start = time.time()
p = Pool()
for i in range(8): # CPU有几核,每次就取出几个进程
p.apply_async(func=Tasks.long_time_task, args=(i,))
p.close() # 调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了
p.join() # 对Pool对象调用join()方法会等待所有子进程执行完毕
end = time.time()
print('多进程(非阻塞)执行共需时间为:%.2f' % (end-start))
print type(Tasks.long_time_task)
print type(long_time_task)
控制台输出如下:
多进程(非阻塞)执行共需时间为:0.18
<type 'function'>
<type 'function'>
说明什么? 说明虽然静态方法的类型是'function‘,但进程还是没有被执行吗? 这不就麻烦了吗,我就想把多进程封装到类里咋办呢??暂时还没弄明白,等弄明白之后在回来填坑,不过现在发现可以通过“类外部的函数包裹类内静态函数”,这样的包裹方法也可以让子进程执行。代码如下:
import time
from multiprocessing import Pool
class Tasks():
@staticmethod
def long_time_task(name):
print 'task %s starts running' % name
time.sleep(3)
print 'task %s ends running --3 seconds' % name
def long_time_task(name):
Tasks.long_time_task(name)
if __name__ =='__main__':
start = time.time()
p = Pool()
for i in range(8): # CPU有几核,每次就取出几个进程
p.apply_async(func=long_time_task, args=(i,))
p.close() # 调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了
p.join() # 对Pool对象调用join()方法会等待所有子进程执行完毕
end = time.time()
print('多进程(非阻塞)执行共需时间为:%.2f' % (end-start))
print type(Tasks.long_time_task)
print type(long_time_task)