首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python | 事半功倍怎么来呢

Python | 事半功倍怎么来呢

作者头像
用户6825444
发布2019-12-18 11:49:41
3470
发布2019-12-18 11:49:41
举报
文章被收录于专栏:木下学Python木下学Python

在写爬虫时,在数据量比较大时大家一定遇见过爬取速度不理想的问题吧。这次小编以上次的“360图片爬虫”,把它分别改写成了多进程,多线程,以及多线程 + 多进程的爬虫做了一个对比。上一篇链接如下:

爬虫的结构是什么样的呢?

Start

以上是没有加多进程,多线程的串行图片爬虫下载 1000 张图片所需要的时间。

多进程

大家先来看一看多进程是怎么创建的吧~

1.在父进程基础下创建一个进程:

"""
跨平台
提供了一个 Process 类来描述进程对象。创建子进程,只需要传入一个执行函数和函数的参数
,即可完成一个 Process 实例创建,用 start() 方法启动进程,用 join() 方法实现进程
间的同步
"""
import os
from multiprocessing import Process


#子进程要执行的代码
def run_proc(name):
    print('Child process %s (%s) Running ...' % (name,os.getpid())) # os.getpid() 获取进程 id


if __name__ == '__main__':
    print('Parent process %s.' % os.getpid())
    for i in range(5):
        p = Process(target=run_proc,args=(str(i),)) # 第一个参数为任务函数,第二个为传进去的任务参数
        print('Process will start.')
        p.start()
    p.join()
    print('Process end.')

2.创建进程池,默认是以计算机有几个 CPU 就创建几个:

"""
Pool 可以提供指定数量的进程供用户调用,默认大小是 CPU 的核数。但有新的请求提交到
Pool 中时,池还没有满,就会创建一个新的进程用来执行该请求;如已达到最大数,就会等待
知道有进程结束,才会创建新的进程来处理他
"""
from multiprocessing import Pool
import os,time,random


def run_task(name):
    print('Task %s (pid = %s) is running ...' % (name,os.getpid()))
    time.sleep(random.random() * 3)
    print('Task %s end.' % name)


if __name__ == '__main__':
    print('Current process %s.' % os.getpid())
    p = Pool(processes=3)
    for i in range(5):
        p.apply_async(run_task,args=(i,)) #添加进程任务,i 为传进去的进程任务的参数
        pass
    print('Waiting for all subprocesses done...')
    p.close() #不再添加新进程
    p.join() #等待所有子进程执行完毕,调用之前必须先调用 close(),针对 Pool 对象
    print('All subprocesses done.')

以上就是多进程的创建,小编得爬虫以这样的基础修改后的运行时间提升了一般如下:

多线程

大家先来看一看多线程是怎么创建的吧~

方法一:

"""
把一个函数传入并创建 Tread 实例
"""
import random
import time,threading


#新线程执行的代码
def thread_run(urls):
    print('Current %s is running...' % threading.current_thread().name)
    for url in urls:
        print('%s --->>> %s' % (threading.current_thread().name,url))
        time.sleep(random.random())
    print('%s ended.' % threading.current_thread().name)


print('%s is runnung...' % threading.current_thread().name)
t1 = threading.Thread(target=thread_run,name='Thread_1',args=(['url_1',
                            'url_2','url_3'],))
t2 = threading.Thread(target=thread_run,name='Thread_2',args=(['url_4',
                            'url_5','url_6'],))
t1.start()
t2.start()
t1.join()
t2.join()
print('%s ended.' % threading.current_thread().name)

方法二:

"""
从 treading.Thread 继承创建线程类
"""
import random
import threading
import time


class myThreading(threading.Thread):
    def __init__(self,name,urls):
        threading.Thread.__init__(self,name=name) #初始化线程
        self.urls = urls

    def run(self):
        print('Current %s is running...' % threading.current_thread().name)
        for url in self.urls:
            print('%s --->>> %s' % (threading.current_thread().name,url))
            time.sleep(random.random())
        print('%s ended.' % threading.current_thread().name,url)


print('%s is running...' % threading.current_thread().name)
t1 = myThreading(name='Tread_1',urls=['url_1','url_2','url_3'])
t2 = myThreading(name='Tread_2',urls=['url_4','url_5','url_6'])
t1.start()
t2.start()
t1.join()
t2.join()
print('%s ended.' % threading.current_thread().name)

以上是多线程的两种创建方法,小编的爬虫以此为基础修改后,有一个疑惑,速度并没有提升太多,还比串行慢了:

多进程 + 多线程

小编把串行爬虫改成了多进程 + 多线程,发现,比只用多进程快了 2 秒,速度又提升了一点。

这里多进程是用在请求网页,而多线程是用在了图片下载。

End

多进程:

用多进程速度会有显著提升,多进程一般用于计算密集型(for 循环这些),在爬虫中,一般用于请求的 url 列表。

多线程:

单独用多线程用于爬虫速度没有太大的改变,多线程一般用于 I/O 密集型(文件读写这些),在爬虫中一般有读写文件,下载图片,视频音乐。

多进程 + 多线程:

两者结合在适合的地方使用,速度会有所改变,不是任何程序都一定用,要对症下药嘛。小编这个爬虫两者结合,速度虽然只提升了 2 秒,但也是有所改变。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 木下学Python 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档