request+多任务异步协程爬虫

85 阅读4分钟

进程,线程,协程概念简述

多进程:对系统的cup资源进行最大的利用

多线程:对系统分配给当前进程的cup资源进行最大限度的运用

window 核心是主多线程 liunx核心主是多进程,每一个请求开出一个进程

可用将多进程理解为多个人多张桌子吃饭

多线程可用理解为多个人在同一张桌子吃饭

进程是系统资源分配的基本单位,线程是进程资源分配的基本单位

协程,又称微线程,纤程,英文名Coroutine。协程的作用是在执行函数A时可以随时中断去执行函数B,然后中断函数B继续执行函数A(可以自由切换)。但这一过程并不是函数调用,这一整个过程看似像多线程,然而协程只有一个线程执行

协程与线程的区别

  1. 由于协程的特性, 适合执行大量的I/O 密集型任务, 而线程在这方面弱于协程
  2. 协程涉及到函数的切换, 多线程涉及到线程的切换, 所以都有执行上下文, 但是协程不是被操作系统内核所管理, 而完全是由程序所控制(也就是在用户态执行), 这样带来的好处就是性能得到了很大的提升, 不会像线程那样需要在内核态进行上下文切换来消耗资源,因此协程的开销远远小于线程的开销
  3. 同一时间, 在多核处理器的环境下, 多个线程是可以并行的,但是运行的协程的函数却只能有一个其他的协程的函数都被suspend, 即协程是并发的
  4. 由于协程在同一个线程中, 所以不需要用来守卫临界区段的同步性原语(primitive)比如互斥锁、信号量等,并且不需要来自操作系统的支持
  5. 在协程之间的切换不需要涉及任何系统调用或任何阻塞调用
  6. 通常的线程是抢先式(即由操作系统分配执行权) , 而协程是由程序分配执行权

那协程有什么优势呢?

  • 执行效率极高,因为子程序切换(函数)不是线程切换,由程序自身控制,没有切换线程的开销。所以与多线程相比,线程的数量越多,协程性能的优势越明显。
  • 不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在控制共享资源时也不需要加锁,因此执行效率高很多

多任务异步协程套路(主要用requests 进行url获取,aiohttp对url进行异步解析)

async

用来声明一个函数为异步函数,异步函数的特点是能在函数执行过程中挂起,去执行其他异步函数,等到挂起条件

async 可以将函数变为一个特殊函数(1,该特殊函数被调用后,函数内部不会立即执行。2,该函数被调用后会返回一个协程对象。3,协程即一组指定的操作。4,任务对象就是高级协程对象)

await

用来用来声明程序挂起,比如异步程序执行到某一步时需要等待的时间很长,就将此挂起,去执行其他的异步程序(耗时认为都建议挂起

协程案例

python 源码

import asyncio

import requests

import time

async def result(url):

res = await request_url(url)

print(url, res)

async def request_url(url):

res = requests.get(url, proxies={'https': None, 'http': None}, verify=False)

print(url)

await asyncio.sleep(2)

print("execute_time:", time.time() - start)

return res

url_list = ["www.csdn.net/",

"blog.csdn.net/qq_43380180…

"www.baidu.com/",

]

start = time.time()

print(f"start_time:{start}\n")

task = [result(url) for url in url_list]

loop = asyncio.get_event_loop()

loop.run_until_complete(asyncio.wait(task))

endtime = time.time() - start

print("\nendtime:", time.time())

print("all_execute_time:", endtime)

import requests ,asyncio,time,aiohttp (支持异步的网络请求模块)

urls=['www.baidu.com','www.hao123.com','www.bing.com']

async def get_request(url):

async with aiohttp.ClientSession() as sess:

async with sess.get(url=url) as response:

page_text=await response.text()

return page_text

if name == 'main':

start=time.time()

tasks=[]

for url in urls:

c=get_request(url)

task=asyncio.ensure_future(c)(创建任务对象)

tasks.append(task)

loop=asyncio.get_event_loop() (注册事件循环,可以将多个任务对象注册或装载到时间循环对象中,开启事件循环,其内部任务则会被基于异步进行执行)

loop.run_until_complete(asyncio.wait(tasks))(注册和启动)

print('总耗时:',time.time()-start)

import threading
import asyncio


async def myfun(index):
    print(f'[{index}]({threading.currentThread().name})')
    await asyncio.sleep(1)
    return index


def getfuture(future):
    print(future.result())


loop = asyncio.get_event_loop()
tasks = []
for item in range(10):
    future = asyncio.ensure_future(myfun(item))
    tasks.append(future)
    future.add_done_callback(getfuture)
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

D:\项目文件\python.exe D:\项目文件\new_project\XM\spider\demo.py

0

1

2

3

4

5

6

7

8

9

0

2

6

9

8

5

7

4

1

3

Process finished with exit code 0

简单总结

进程是资源分配的单位

线程是操作系统调度的单位

进程切换需要的资源很最大,效率很低

线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)

协程切换任务资源很小,效率高

多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发