zoukankan      html  css  js  c++  java
  • python-协程

    多协程的用法

    1.gevent库

    对比同步执行:

     1 import requests,time
     2 #导入requests和time
     3 start = time.time()
     4 #记录程序开始时间
     5 
     6 url_list = ['https://www.baidu.com/',
     7 'https://www.sina.com.cn/',
     8 'http://www.sohu.com/',
     9 'https://www.qq.com/',
    10 'https://www.163.com/',
    11 'http://www.iqiyi.com/',
    12 'https://www.tmall.com/',
    13 'http://www.ifeng.com/']
    14 #把8个网站封装成列表
    15 
    16 for url in url_list:
    17 #遍历url_list
    18     r = requests.get(url)
    19     #用requests.get()函数爬取网站
    20     print(url,r.status_code)
    21     #打印网址和抓取请求的状态码
    22 
    23 end = time.time()
    24 #记录程序结束时间
    25 print(end-start)
    26 #end-start是结束时间减去开始时间,就是最终所花时间。
    27 #最后,把时间打印出来。

    多协程执行:

     1 from gevent import monkey
     2 #从gevent库里导入monkey模块。
     3 monkey.patch_all()
     4 #monkey.patch_all()能把程序变成协作式运行,就是可以帮助程序实现异步。
     5 import gevent,time,requests
     6 #导入gevent、time、requests。
     7 
     8 start = time.time()
     9 #记录程序开始时间。
    10 
    11 url_list = ['https://www.baidu.com/',
    12 'https://www.sina.com.cn/',
    13 'http://www.sohu.com/',
    14 'https://www.qq.com/',
    15 'https://www.163.com/',
    16 'http://www.iqiyi.com/',
    17 'https://www.tmall.com/',
    18 'http://www.ifeng.com/']
    19 #把8个网站封装成列表。
    20 
    21 def crawler(url):
    22 #定义一个crawler()函数。
    23     r = requests.get(url)
    24     #用requests.get()函数爬取网站。
    25     print(url,time.time()-start,r.status_code)
    26     #打印网址、请求运行时间、状态码。
    27 
    28 tasks_list = [ ]
    29 #创建空的任务列表。
    30 
    31 for url in url_list:
    32 #遍历url_list。
    33     task = gevent.spawn(crawler,url)
    34     #用gevent.spawn()函数创建任务。
    35     tasks_list.append(task)
    36     #往任务列表添加任务。
    37 gevent.joinall(tasks_list)
    38 #执行任务列表里的所有任务,就是让爬虫开始爬取网站。
    39 end = time.time()
    40 #记录程序结束时间。
    41 print(end-start)
    42 #打印程序最终所需时间。

    第1、3行代码:从gevent库里导入了monkey模块,这个模块能将程序转换成可异步的程序。monkey.patch_all(),它的作用其实就像你的电脑有时会弹出“是否要用补丁修补漏洞或更新”一样。它能给程序打上补丁,让程序变成是异步模式,而不是同步模式。它也叫“猴子补丁”。

    第5行代码:我们导入了gevent库来帮我们实现多协程,导入了time模块来帮我们记录爬取所需时间,导入了requests模块帮我们实现爬取8个网站。

    第21、23、25行代码:我们定义了一个crawler函数,只要调用这个函数,它就会执行【用requests.get()爬取网站】和【打印网址、请求运行时间、状态码】这两个任务。

    第33行代码:因为gevent只能处理gevent的任务对象,不能直接调用普通函数,所以需要借助gevent.spawn()来创建任务对象。

    这里需要注意一点:gevent.spawn()的参数需为要调用的函数名及该函数的参数。比如,gevent.spawn(crawler,url)就是创建一个执行crawler函数的任务,参数为crawler函数名和它自身的参数url。

    第35行代码:用append函数把任务添加到tasks_list的任务列表里。

    第37行代码:调用gevent库里的joinall方法,能启动执行所有的任务。gevent.joinall(tasks_list)就是执行tasks_list这个任务列表里的所有任务,开始爬取

    总结一下用gevent实现多协程爬取的重点:

    queue模块

    当我们用多协程来爬虫,需要创建大量任务时,我们可以借助queue模块。

    queue翻译成中文是队列的意思。我们可以用queue模块来存储任务,让任务都变成一条整齐的队列,就像银行窗口的排号做法。因为queue其实是一种有序的数据结构,可以用来存取数据。

    这样,协程就可以从队列里把任务提取出来执行,直到队列空了,任务也就处理完了。就像银行窗口的工作人员会根据排号系统里的排号,处理客人的业务,如果已经没有新的排号,就意味着客户的业务都已办理完毕。

    接下来,我们来实操看看,可以怎么用queue模块和协程配合,依旧以抓取8个网站为例。

     1 from gevent import monkey
     2 monkey.patch_all()
     3 import gevent,time,requests
     4 from gevent.queue import Queue
     5 
     6 start = time.time()
     7 
     8 url_list = ['https://www.baidu.com/',
     9 'https://www.sina.com.cn/',
    10 'http://www.sohu.com/',
    11 'https://www.qq.com/',
    12 'https://www.163.com/',
    13 'http://www.iqiyi.com/',
    14 'https://www.tmall.com/',
    15 'http://www.ifeng.com/']
    16 
    17 work = Queue()
    18 for url in url_list:
    19     work.put_nowait(url)
    20 
    21 def crawler():
    22     while not work.empty():
    23         url = work.get_nowait()
    24         r = requests.get(url)
    25         print(url,work.qsize(),r.status_code)
    26 
    27 tasks_list  = [ ]
    28 
    29 for x in range(2):
    30     task = gevent.spawn(crawler)
    31     tasks_list.append(task)
    32 gevent.joinall(tasks_list)
    33 
    34 end = time.time()
    35 print(end-start)

    因为gevent库里就带有queue,所以我们用【from gevent.queue import Queue】就能把queue模块导入。其他模块和代码我们在讲解gevent时已经讲解过了,相信你能懂。

    用Queue()能创建queue对象,相当于创建了一个不限任何存储数量的空队列。如果我们往Queue()中传入参数,比如Queue(10),则表示这个队列只能存储10个任务。

    创建了queue对象后,我们就能调用这个对象的put_nowait方法,把我们的每个网址都存储进我们刚刚建立好的空队列里。

    work.put_nowait(url)这行代码就是把遍历的8个网站,都存储进队列里。

    这里定义的crawler函数,多了三个你可能看不懂的代码:1.while not work.empty():;2.url = work.get_nowait();3.work.qsize()

    这三个代码涉及到queue对象的三个方法:empty方法,是用来判断队列是不是空了的;get_nowait方法,是用来从队列里提取数据的;qsize方法,是用来判断队列里还剩多少数量的。

    当然,queue对象的方法还不止这几种,比如有判断队列是否为空的empty方法,对应也有判断队列是否为满的full方法。

  • 相关阅读:
    ORACLE中seq$表更新频繁的分析
    VmWare平台Windows Server 2012 无响应宕机
    SQL Challenge ——快速找到1-100之间缺失的数
    ORACLE推导参数Derived Parameter介绍
    SQL SERVER 数据库各版本功能对比
    Jsp中格式化时间戳的常用标签
    SQL Server 2014 Database Mail重复发送邮件特殊案例
    采用HTML5之“data
    多线程之策略模式
    docker attach卡住,和exec的选择
  • 原文地址:https://www.cnblogs.com/mylearning-log/p/10893597.html
Copyright © 2011-2022 走看看