python使用协程与不使用协程的对比

为什么使用gevent
  • Python通过yield提供了对协程的基本支持,但是不完全。比如python的yield虽然提供了对协程的支持,但是需要用send手动发送数据(比如io操作时的切换,需要发送 “耗时操作完成”告诉程序可以继续往下走),才能改变程序的执行流程,,而第三方的gevent为Python提供了比较完善的协程支持。
gevent的优点
  • gevent是第三方库,通过greenlet实现协程,其基本思想是:
    当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。
    由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch(猴子补丁)完成。
案例:爬取51job
  • 代码如下
import gevent
from gevent import monkey
# 将【标准库-阻塞IO实现】替换为【gevent-非阻塞IO实现】
monkey.patch_all()

import requests
from lxml import etree
import time

def get_51info(page):
    url = f"https://search.51job.com/list/020000,000000,0000,00,9,99,python,2,{page}.html?lang=c&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare="
    resp = requests.get(url)
    html_str = resp.content.decode("gbk")
    root = etree.HTML(html_str)
    job_list = root.xpath('//div[@id="resultList"]/div[@class="el"]')

    for job in job_list:
        position = job.xpath('./p/span/a/@title')
        company_name = job.xpath('./span[@class="t2"]/a/@title')
        salary = job.xpath('./span[@class="t4"]/text()')
        # 空列表 空字典 并不等None
        if salary != []:
            print(position[0],company_name[0],salary[0])



if __name__ == '__main__':

    # 不使用协程
    # start = time.time()
    # # print(start)
    # for i in range(1,51):
    #     get_51info(i)
    # end = time.time()
    # # print(end)
    # #over,耗时41.33733057975769秒  不使用协程花费了41秒
    # print(f"over,耗时{(end - start)}秒")

    # 使用协程
    start = time.time()
    # 协程传递参数,(方法名,参数。。。)
    gevent.joinall(
        [gevent.spawn(get_51info,i) for i in range(1,51)]
    )
    end = time.time()
    #over,耗时13.129491090774536秒  使用协程花费了19秒
    print(f"over,耗时{(end - start)}秒")

经过测试,不使用协程时(单线程)爬取50页岗位信息花费41秒,使用协程时(单线程中实现了多个协程对象)花费了13秒,

  • 因为GIL锁的存在,python的多线程一个时刻只有一个线程执行,而单线程中实现了多协程,协程是程序级别的,协程的切换效率很高,不受GIL锁的影响,所以可以极大的提升执行效率
  • 附:在Python多线程下,每个线程的执行方式:
    1、获取GIL
    2、执行代码直到sleep或者是python虚拟机将其挂起。
    3、释放GIL
    可见,某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值