专栏首页木下学PythonPython | 事半功倍怎么来呢

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 秒,但也是有所改变。

本文分享自微信公众号 - 木下学Python(zjk_py),作者:木下瞳

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-05-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

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

    在软件工程中,有着这么几个字“高内聚低耦合”,意思就是说:大模块分割成一个个小模块实现,每一个模块之间的独立性较高,修改某个模块,对其他模块或整个项目影响较小。

    用户6825444
  • Python 脚本 GUI 界面生成工具

    对于一些 Python 脚本,我们想把它打包给其他人使用,不是黑色的命令行框,而是打包成一个有界面的程序包给别人,让普通用户也能用上是多么酷的事啊。

    用户6825444
  • Python之京东商品图片爬虫

    京东是我们购物经常去光顾的一个点上平台,它里面的商品多种多样,其中的商品图片也是应有尽有,今天小编呢就给大家带来一个京东商品图片的简单爬虫。

    用户6825444
  • 【C语言笔记】数组与指针不等价

    数组遍历方式一:使用指针遍历数组元素,p++等价于(p++),即指针指向的地址每次后移一个单位,然后再取地址上的值。这里的一个单位是sizeof(int)个字节...

    正念君
  • Python-时间及日期-01-当前年月日时分秒

    系统:Windows 7 语言版本:Anaconda3-4.3.0.1-Windows-x86_64 编辑器:pycharm-community-2016.3....

    zishendianxia
  • centos下安装phpredis扩展

    Marser
  • 【ionic+angularjs】angularjs ui-router路由简介($urlRouter、$state、$stateProvider、ui-sref....)

    之前有写过一篇关于Angular自带的路由:ngRoute。今天来说说Angular的第三方路由:ui-router。那么有人就会问:为什么Ang...

    用户5640963
  • Debian 光盘安装简易教程

    这篇文章我会尽可能详细地说明如何快速安装纯净的Debian 8.2.0,需要懂一点vi编辑器的使用方法。 如果是新手,没用过 vim 编辑器也不用担心,我会尽量...

    Debian社区
  • 入门 | 什么是最大似然估计、最大后验估计以及贝叶斯参数估计

    选自Medium 作者:Akihiro Matsukawa 机器之心编译 参与:Geek.ai、刘晓坤 本文以简单的案例,解释了最大似然估计、最大后验估计以及贝...

    机器之心
  • 【案例】最大似然估计、最大后验估计以及贝叶斯参数估计的联系和区别

    假如你有一个硬币。你把它投掷 3 次,出现了 3 次正面。下一次投掷硬币正面朝上的概率是多少? 这是一个从数据中估计参数的基础机器学习问题。在这种情况下,我们要...

    机器人网

扫码关注云+社区

领取腾讯云代金券