Python 多进程池的学习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011964923/article/details/53708653

最近想用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)





猜你喜欢

转载自blog.csdn.net/u011964923/article/details/53708653