python实用技巧之任务切分
Python 大任务切分小任务
今天来说说,Python中的任务切分。以爬虫为例,从一个存 url 的 txt 文件中,读取其内容,我们会获取一个 url 列表。我们把这一个 url 列表称为大任务。
列表切分
在不考虑内存占用的情况下,我们对上面的大任务进行一个切分。比如我们将大任务切分成的小任务是每秒最多只访问5个URL。
import os
import time
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
def read_file():
file_path = os.path.join(CURRENT_DIR, "url_list.txt")
with open(file_path, "r", encoding="utf-8") as fs:
result = [i.strip() for i in fs.readlines()]
return result
def fetch(url):
print(url)
def run():
max_count = 5
url_list = read_file()
for index in range(0, len(url_list), max_count):
start = time.time()
fetch(url_list[index:index + max_count])
end = time.time() - start
if end < 1:
time.sleep(1 - end)
if __name__ == '__main__':
run()
关键代码都在for循环里,首先我们通过声明range的第三个参数,该参数指定迭代的步长为5,这样每次index增加都是以5为基数,即0,5,10。。。
然后我们对url_list做切片,每次取其五个元素,这五个元素会随着index的增加不断的在改变,如果最后不够五个了,按照切片的特性这个时候就会有多少取多少了,不会造成索引超下标的问题。
随着url列表的增加,我们会发现内存的占用也在提高了。这个时候我们就需要对代码进行修改了,我们知道生成器是比较节省内存的空间的,修改之后代码变成,下面的这样。
生成器切分
# -*- coding: utf-8 -*-
# @时间 : 2019-11-23 23:47
# @作者 : 陈祥安
# @文件名 : g.py
# @公众号: Python学习开发
import os
import time
from itertools import islice
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
def read_file():
file_path = os.path.join(CURRENT_DIR, "url_list.txt")
with open(file_path, "r", encoding="utf-8") as fs:
for i in fs:
yield i.strip()
def fetch(url):
print(url)
def run():
max_count = 5
url_gen = read_file()
while True:
url_list = list(islice(url_gen, 0, max_count))
if not url_list:
break
start = time.time()
fetch(url_list)
end = time.time() - start
if end < 1:
time.sleep(1 - end)
if __name__ == '__main__':
run()
首先,我们修改了文件读取的方式,把原来读列表的形式,改为了生成器的形式。这样我们在调用该文件读取方法的时候大大节省了内存。
然后就是对上面for循环进行改造,因为生成器的特性,这里不适合使用for进行迭代,因为每一次的迭代都会消耗生成器的元素,通过使用itertools的islice对url_gen进行切分,islice是生成器的切片,这里我们每次切分出含有5个元素的生成器,因为生成器没有__len__方法所以,我们将其转为列表,然后判断列表是否为空,就可以知道迭代是否该结束了。
修改之后的代码,不管是性能还是节省内存上都大大的提高。读取千万级的文件不是问题。
除此之外,在使用异步爬虫的时候,也许会用到异步生成器切片。下面就和大家讨论,异步生成器切分的问题
异步生成器切分
首先先来看一个简单的异步生成器。
我们知道调用下面的代码会得到一个生成器
def foo():
for i in range(20):
yield i
如果在def前面加一个async,那么在调用的时候它就是个异步生成器了。
完整示例代码如下
import asyncio
async def foo():
for i in range(20):
yield i
async def run():
async_gen = foo()
async for i in async_gen:
print(i)
if __name__ == '__main__':
asyncio.run(run())
关于async for的切分有点复杂,这里推荐使用aiostream模块,使用之后代码改为下面这样
import asyncio
from aiostream import stream
async def foo():
for i in range(22):
yield i
async def run():
index = 0
limit = 5
while True:
#测试发现foo应该是个callable类型,并且运行之后是个async_generator。
xs = stream.iterate(foo())
ys = xs[index:index + limit]
t = await stream.list(ys)
if not t:
break
print(t)
index += limit
await asyncio.sleep(0.01)
if __name__ == '__main__':
asyncio.run(run())
python实用技巧之任务切分的更多相关文章
- Python 实用技巧
模块相关 导入模块时,可以通过模块的 __file__ 属性查看模块所在磁盘的路径位置,参考:关于Python包和模块的10个知识清单 Pip 安装Pip 方法一: sudo apt-get purg ...
- Python实用技巧
1.改变工作目录 import os os.chdir('C:/Users/Mr.Zhao') 2.搜索制定目录下的文件 1 import glob 2 glob.glob('C:/User/Mr.Z ...
- python 实用技巧:几十行代码将照片转换成素描图、随后打包成可执行文件(源码分享)
效果展示 原始效果图 素描效果图 相关依赖包 # 超美观的打印库 from pprint import pprint # 图像处理库 from PIL import Image # 科学计算库 imp ...
- python实用技巧 : Filtering os.walk(转)
''' Created on Mar 7, 2010 @author: Diego 需求: 得到某个目录下, 符合过滤条件的文件夹/文件.实现: 将os.walk再次包装. TODO: 不知道本程序的 ...
- python实用30个小技巧
python实用30个小技巧 展开1.原地交换两个数字Python 提供了一个直观的在一行代码中赋值与交换(变量值)的方法,请参见下面的示例: In [1]: x,y = 10 ,20 In [2]: ...
- 「Python实用秘技07」pandas中鲜为人知的隐藏排序技巧
本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的系列文章「Python实用秘技」的第7期 ...
- iOS开发实用技巧—在手机浏览器头部弹出app应用下载提示
iOS开发实用技巧—在手机浏览器头部弹出app应用下载提示 本文介绍其简单使用: 第一步:在本地建立一个访问的服务端. 打开本地终端,在本地新建一个文件夹,在该文件夹中存放测试的html页面. ...
- JavaScript函数作用域与对象以及实用技巧
1. JS作用域 1.1 全局作用域和局部作用域 函数外面声明的就是 全局作用域 函数内是局部作用域 全局变量可以直接在函数内修改和使用 变量,使用var是声明,没有var是使用变量. 如果在函数内使 ...
- 「Python实用秘技01」复杂zip文件的解压
本文完整示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/PythonPracticalSkills 这是我的新系列文章「Python实用秘技」的第1 ...
随机推荐
- ActiveMQ 认证与授权
使用ActiveMQ自带simpleAuthenticationPlugin 1.直接将用户名密码写入activemq.xml文件 <plugins> <simpleAuthenti ...
- ios开发之NSData
NSData用于保存字节数组. 初始化 - (instancetype)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length free ...
- tp5 隐藏index.php
原文——>链接 官方默认的.htaccess文件 <IfModule mod_rewrite.c> Options +FollowSymlinks -Multiviews Rewri ...
- 空指针异常:解决 RequestContextHolder.getRequestAttributes()为空的问题
现象:实现Feign请求拦截器时,执行如下代码,报空指针异常 ServletRequestAttributes attributes = (ServletRequestAttributes) Requ ...
- c#中关于textbox换行
要让一个Windows Form的TextBox显示多行文本就得把它的Multiline属性设置为true. 这个大家都知道,可是当你要在代码中为Text属性设置多行文本[的时候可能会遇到点麻烦:) ...
- centos 安装vsftp 服务
安装软件yum install vsftpd -y 启动测试 # systemctl start vsftpd# netstat -nultp | grep 21tcp 0 0 0.0.0.0:21 ...
- [LeetCode] 0279. Perfect Squares 完全平方数
题目 Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9 ...
- 5、Hadoop 2.6.5 环境搭建
下载 地址:http://archive.apache.org/dist/hadoop/common/ sudo wget http://archive.apache.org/dist/hadoop/ ...
- 洛谷 P1886 滑动窗口 题解
每日一题 day26 打卡 Analysis 单调队列模板 对于每一个区间,有以下操作: 1.维护队首(就是如果你已经是当前的m个之前那你就可以被删了,head++) 2.在队尾插入(每插入一个就要从 ...
- learning java 获取环境变量及系统属性
通过System.getenv( ) 获取环境变量 通过System.getProperties() 获取系统属情 通过System.currentTimeMillis() System.nanoT ...