第五周——爬虫入门 Day5 7.29

学习时间:9:00——11:00             16:00——19:30

补充概念:进程、线程

进程:一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。

线程:进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。

本质区别:Windows系统中,进程只是资源的分配单位,而线程才是CPU调度运行的基本单位。线程也被称为轻量级进程。

举个例子,进程就像是一个工厂,而线程就是工厂里的流水线,一个工厂里可以有多条流水线,这些流水线共享资源和数据,而不同进程也就是不同的工厂,有各自独立的内存空间,相互独立。

多个进程的程序,调度依然是按照多个线程去进行调度,由于CPU时间片分配给每个独立调度的线程,拥有四个线程的进程比拥有一个线程的进程会拥有更多的CPU时间片,就像原本只有一条流水线,现在同时有四条流水线运行,自然也就达到了加速程序的效果。就CPU利用率来讲,如果一个有四个线程的进程运行在一个四核的CPU机器上,那么核的利用率可以达到100%,即所有的核都可以调度运行一个线程, 不会出现一方有难,八方围观的情况。同样,四个单线程进程也能使四核的CPU机器计算资源利用率达到100%,因为每个进程中的线程被独立调度执行。

一个进程崩溃,并不会影响其他的进程,这也很好理解,因为进程是一个个独立运行的程序,彼此独立,就像是不同行业的工厂,一个倒闭,其余的并不受影响,而线程不然,一个流水线的加工出现问题,那么整个工厂生产的产品都会受到影响,进而整个工厂倒闭。

1.协程
协程不是计算机提供,程序员人为创造。
协程(Coroutine),也可以被称为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是通过一个线程实现代码块相互切换执行。比线程更加轻量级,一个线程也可以拥有多个协程。


实现协程有这么几种方法:

greenlet,早期模块

yield关键字

asyncio装饰器(python3.4及以后,但3.8后被弃用)

async&await关键字(python3.5及以后)(推荐方法)

现在常用greenlet和async&await关键字

greenlet实现协程

from greenlet import greenlet

def func1():
    print(1)
    gr2.switch()             #切换到func2函数
    print(2)
    gr2.switch()

def func2():
    print(3)
    gr1.switch()             #切换到func1函数
    print(4)

gr1 = greenlet(func1)         
gr2 = greenlet(func2)

gr1.switch()                  #先执行func1


#输出结果:1、3、2、4

yield关键字实现协程

def func1():
    yield 1
    yield from func2()      #切换到func2
    yield 2

def func2():
    yield 3
    yield 4

f1 = func1()
for item in f1:
    print(item)

#输出结果:1、3、4、2

async&await实现协程

import asyncio

async def func1():
    print(1)
    await asyncio.sleep(1)      #遇到IO耗时操作,自动切换到tasks的其他任务中
    print(2)

async def func2():
    print(3)
    await asyncio.sleep(1)      #遇到IO耗时操作,自动切换到tasks的其他任务中
    print(4)

tasks = [asyncio.ensure_future(func1()),asyncio.ensure_future(func2())]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

#输出结果:1、3、2、4

原理是导入asyncio模块,之后将定义好的多个函数传到asyncio.ensure_future()的参数中,然后将他们封装在一个任务列表中,然后调用这个任务列表。

这个协程的巧妙之处在于遇到阻塞操作时可以自动切换任务,假如分别在func1的print(1)语句、func2的print(3)语句后面均加上一个下载图片(假设图片下载时间为1秒)的网络IO请求,那么这段代码执行时,会先打印1,然后发送第一个下载请求,由于阻塞,会自动切换到func2中,打印3,然后再次发送第二个打印请求,此时经过1秒钟,图片1、2均下载完成,相比单线程操作节省了1秒钟!!

这样做在于充分压榨单线程的时间,达到多线程的效果,弊端是会频繁访问,加大了ip被封掉的可能性,所以需要ip伪装

协程的意义:在一个线程中如果遇到IO等待时间,线程不会傻等,而是去干点别的事。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值