首页 > 编程语言 >Python爬虫如何实现多线程异步

Python爬虫如何实现多线程异步

时间:2022-11-23 14:03:20浏览次数:47  
标签:异步 code Python 执行 任务 线程 进程 多线程

如果自己的电脑配置高操作系统可以多任务运行的,应该首先要考虑单核CPU是怎么执行多任务的,操作系统会让各个任务交替执行。例如:任务1执行0.02秒,切换到任务2,任务2执行0.02秒,再切换到任务3,执行0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度非常快,给人的感觉就像所有任务都在同时执行一样。真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。

对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。由于每个进程至少要干一件事,所以一个进程至少有一个线程。多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样,真正能同时执行多线程需要多核CPU才可能实现。

我们前面编写的所有的Python程序,都是执行单任务的进程,也就是只有一个线程。如果要同时执行多个任务有3种方案:一种是启动多个进程,每个进程只开一个线程,但多个进程可以一块执行多个任务。还有一种方法是启动一个进程,在一个进程内启动多个线程,多个线程也可以一块执行多个任务。第三种方法,就是启动多个进程,每个进程再启动多个线程,这样同时执行的任务就更多了,这种模型很复杂,实际很少采用。多任务的实现有3种方式:多进程模式;多线程模式;多进程+多线程模式。同时执行多个任务通常各个任务之间需要相互通信和协调,有时,任务1必须暂停等待任务2完成后才能继续执行,有时,任务3和任务4又不能同时执行,所以,多进程和多线程的程序的复杂度要远远高于我们前面写的单进程单线程的程序。因为复杂度高,调试困难,所以,不是迫不得已,我们也不想编写多任务。但是,有很多时候,没有多任务还真不行。想想在电脑上看电影,就必须由一个线程播放视频,另一个线程播放音频,否则,单线程实现的话就只能先把视频播放完再播放音频,或者先把音频播放完再播放视频,这显然是不行的。

Python既支持多进程,又支持多线程。多任务可以由多进程完成,也可以由一个进程内的多线程完成。进程是由若干线程组成的,一个进程至少有一个线程。由于线程是操作系统直接支持的执行单元,因此,高级语言通常都内置多线程的支持,Python也不例外,并且,Python的线程是真正的Posix Thread,而不是模拟出来的线程。Python的标准库提供了两个模块:thread和threading,thread是低级模块,threading是高级模块,对thread进行了封装。绝大多数情况下,我们只需要使用threading这个高级模块。启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行。

import requests
import threading

def get_stock(code):
url = 'http://hq.sinajs.cn/list=' + code
resp = requests.get(url)
print('%s\n' % resp.text)

#多线程异步,加速抓取
#根据有几个股piao代码,就创建几个线程
codes = ['sz000878', 'sh600993', 'sz000002', 'sz002230']
threads = [threading.Thread(target=get_stock, args=(code, )) for code in codes]
#Thread创建线程实例
'''
threads=[ ]
for code in codes:
thread=threading.Thread(target=get_stock,args=(code, ))
threads.append(thread)
'''
for t in threads:
t.start() #启动一个线程
for t in threads:
t.join() #等待每个线程执行结束

多任务用线程池自动调度

import requests
import threadpool #线程池

def get_stock(code):
url = 'http://hq.sinajs.cn/list=' + code
resp = requests.get(url)
print('%s\n' % resp.text)

codes = ['sz000878', 'sh600993', 'sz000002', 'sz002230']
#codes里任务很多,比如几百个,让pool自己去调度
pool = threadpool.ThreadPool(2) #线程池设置,最多同时跑两个线程
tasks = threadpool.makeRequests(get_stock, codes)
#makeRequests构造线程task请求,第一个参数是线程函数,第二个是参数数组
[pool.putRequest(task) for task in tasks]
#列表推导式,putRequest向线程池里加task,让pool自己去调度task
pool.wait() #等所有任务结束

异步  

交出当前CPU的控制权,最大化利用当前单个CPU的效率

import aiohttp #表示http请求是异步方式去请求的
import asyncio #当异步请求返回时,通知异步操作完成

#异步可以参考grequests库的使用:https://github.com/kennethreitz/grequests
async def get_stock(code):
#关键字async表示请求是异步的
url = 'http://hq.sinajs.cn/list=' + code
resp = await aiohttp.request('GET', url) # yield
#await表示任务等待时,不占用CPU资源,通知请求返回
body = await resp.read()
#表示从网络上把请求的东西都读回来
text = body.decode('gb2312') #对读回来的原始字节解码
print(text)
resp.close()

codes = ['sz000878', 'sh600993', 'sz000002', 'sz002230']
tasks = [get_stock(code) for code in codes]
#由于是异步请求,这里get_stock(code)并不会被马上执行,只是占用了一个位置

loop = asyncio.get_event_loop() #loop的作用是——做完任务,事件通知
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

#tasks生成一组并发的异步任务,loop表示异步作用完成后等待通知

标签:异步,code,Python,执行,任务,线程,进程,多线程
From: https://blog.51cto.com/u_13488918/5881184

相关文章

  • 通过Python实现MySQL和PG数据比对
    生产上,有个需要从MySQL异构复制数据到PG中的需求。数据同步组件用的是go-mysql-postgres(两位前同事基于社区开源的go-mysql-elasticsearch上做的PG功能补丁)。目前测试环境......
  • python编程(改进的线程同步方式)
      在实际代码开发中,gui的代码并不好写。因为不管是mvc、还是mvp都有一定的局限性。那么,这个时候,我就在想,是不是可以用mvp+reactor的方法进行gui的改进操作呢?首先app编写......
  • 多线程的那点儿事(之大结局)
      多线程一直是我比较喜欢的话题,当然也是很多朋友比较害怕的话题。喜欢它,因为它确实可以提高pc的使用效率;讨厌它,因为如果对它处理不好,反而会导致更大的麻烦。这里断断续......
  • 多线程的那点儿事(之多核编程)
      多核编程并不是最近才兴起的新鲜事物。早在intel发布双核cpu之前,多核编程已经在业内存在了,只不过那时候是多处理器编程而已。为了实现多核编程,人们开发实现了几种多......
  • python编程(orm原理和实践)
    就给出自己对orm的理解。之前廖雪峰给出的code,大家可以通过​​地址​​下载的到。1、orm的使用方法    一般我们使用orm都是这么写代码的,classUser(Model):id=I......
  • python编程(gevent入门)
        大家都知道python脚本执行的时候不是很快,特别是python下面的多线程机制,长久以来一直被大家所诟病。所以,很多同学都在思考python下面有没有什么方法可以让python执行......
  • python编程(巧用装饰器)
        以前没有用过装饰器,也不知道它有什么用。直到最近写了一个log函数,在直到原来python的装饰器可以这么方便。1、原来debug消息的写法    假设有一个process函数,......
  • python编程(类变量和实例变量)
        关于类变量和实例变量,一直不是很清楚。所以,想做几个实验,彻底解决这个问题。为此,我们设计了三个实验。1、直接引用类变量importosimportsysclassA():data=1......
  • python编程(python和c相互调用)
      通常为了扩展python的功能,我们需要将c库移植到python上面。python和c调用一般分成两种情况,一种是python调用c,这种情况最为普遍,也比较简单。另外一种就是c调用python,这......
  • 搜索引擎的那些事(多线程web遍历)
       上面一篇博客当中,我们可以利用单一的线程完成网页的下载。今天,我们打算在此基础上完成多线程的访问和加载操作。使用多线程,倒不是因为这项技术有多牛,主要是因为我们......