aiohttp + asyncio 异步网络请求基本操作
作者:matrix 发布时间:2019-11-26 分类:Python
asyncio
异步操作需要关键字async
,await
。
async
用来声明方法函数,await
用来声明耗时操作。
但是await
关键字后面要求为awaitable对象
且只能在async方法内部使用,不能在外部入口中使用。asyncio的语法其实是系统内部实现了yield from
协程。
aiohttp
用来代替requests的请求库,且支持异步操作。
主要优点体现在并发请求多个耗时任务时,自动安排耗时时的操作,避免cpu等待一个一个请求。
单个请求操作
import aiohttp
import asyncio
#get 请求
async def get():
async with aiohttp.request('GET','https://api.github.com/users/Ho',params={'arg1':123}) as response:
# response.request_info # 请求信息
return await response.json()
rel = asyncio.run(get())
# 或者使用下面方式 手动关闭异步事件循环
# loop = asyncio.get_event_loop()
# rel = loop.run_until_complete(get())
# loop.close()
print(rel)
多个并发请求操作
主要区别在于异步任务的添加操作,运行。
请求测试url:
http://link/await/1 # delay 1sec
http://link/await/2 # delay 2sec
...
请求测试:
import aiohttp
import asyncio
#get 请求
async def get():
async with aiohttp.request('GET','http://link/await/1') as response:
return await response.text()
# 所有请求任务
async def all_req():
#async with asyncio.Semaphore(5): 设置并发的连接数
# https://docs.python.org/zh-cn/3/library/asyncio-sync.html#asyncio.Semaphore
task = []
#添加请求任务
for i in range(5):
task.append(asyncio.create_task(get()))
#create_task 方法等同于 ensure_future()方法
#手册建议首选 create_task方法
# https://docs.python.org/zh-cn/3/library/asyncio-future.html?highlight=ensure_future#asyncio.ensure_future
return await asyncio.gather(*task)#传入参数 tuple类型 作为位置参数
# 等同于 asyncio.gather(get(),get())
# gather()方法用于收集所有任务完成的返回值,如果换成wait()方法会返回任务tuple对象,(done,pending)
rel = asyncio.run(all_req())
print(rel)
# 总共5个请求任务返回:
# 总耗时1秒多,相比同步的5秒+好N多。
"""
['sleep 1 second is done', 'sleep 1 second is done', 'sleep 1 second is done', 'sleep 1 second is done', 'sleep 1 second is done']
[Done] exited with code=0 in 1.955 seconds
"""
tell why??
测试发现Semaphore方法设置的请求并发数量跟本不起作用,nginx的access.log
以及Proxifier
看到的一次性请求量都不是代码中设置的数量。
使用uvloop优化异步操作
uvloop用于提升协程的速度。
uvloop使用很简单,直接设置异步策略就好了。
import asyncio
import uvloop
#声明使用 uvloop 事件循环
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
测试遇到很多报错,基本上都是await和async使用的问题。
异步请求的分块chunk并发控制
自行chunk操作
自己按照所有任务的list列表进行chunk切割,然后分块进行请求,每块中固定chunk数量的任务。基本可以实现想要的并发限制操作
async def _bulk_task(num,current_page = 1):
"""批量创建异步任务
"""
task = []
for i in range(num):# 每次10个连接并发进行请求
task.append(asyncio.create_task(get(current_page)))
current_page += 1
return await asyncio.gather(*task)
# 主要进行chunk操作的函数
def run_task(total,chunk,offset_start_page = 1):
"""运行分块处理的批量任务
Arguments:
total int 总请求数
chunk int 每次并发请求数
offset_start_page int 初始分块开始的页数(偏移页数),正常默认为1
Yields:
返回收集的异步任务运行结果
"""
length = math.ceil(total/chunk)
for i in range(length):
start_page = i * chunk + offset_start_page # 当前分块开始的页数
haldle_num = chunk# 当前需要并发处理的数量
#处理结尾的块
if i == length - 1:
# print(':::',chunk,start_page + chunk - offset_start_page)
haldle_num = min(chunk,total + offset_start_page - start_page)
# print('当前分块下标:{},当前分块需要处理的总数:{},当前分块开始页数:{}'.format(i,haldle_num,start_page))
rel = asyncio.run(_bulk_task(haldle_num,start_page))
yield rel
rel = run_task(123,10)# 123总任务 每10条并发请求
for i in rel:
print(i)
独立封装
封装为async_curl类,以后可以直接import使用
https://raw.githubusercontent.com/Hootrix/com.gllue.portal/master/async_curl.py
参考:
https://www.cnblogs.com/Summer-skr--blog/p/11486634.html
https://hubertroy.gitbooks.io/aiohttp-chinese-documentation/content/aiohttp%E6%96%87%E6%A1%A3/ClientUsage.html#%E6%84%89%E5%BF%AB%E5%9C%B0%E7%BB%93%E6%9D%9F
https://docs.Python.org/zh-cn/3/library/asyncio-eventloop.html#asyncio.get_running_loop
https://segmentfault.com/q/1010000008663962
http://www.ruanyifeng.com/blog/2019/11/Python-asyncio.html
https://blog.csdn.net/qq_37144341/article/details/89471603
https://www.jianshu.com/p/8f65e50f39b4
awk入门小记
作者:matrix 发布时间:2019-11-06 分类:command Linux
awk用于unix的文本处理,经常出现和使用。读取每一行文本进行格式化输出。
测试环境 Macos
awk简单操作
默认使用空格进行字符串分割
echo '1 2 3' |awk '{print $0}' # 1 2 3
echo '1 2 3' |awk '{print $3}' # 3
echo -e "1\n2\n3" |awk '/[23]/' #正则条件查找
echo -e "abc\n1a2\n33" |awk '/a/' #正则条件查找字母a
awk '{print $3}' file_path #指定文件
ls -alh|awk '/^d/' #输出目录
# drwxr-xr-x 3 panc staff 96B 7 16 23:32 pt-program
echo '1-2-3' |awk -F '-' '{print $2}' #指定分割符号 - 输出 2
$0
表示当前行
$1
表示第一个分割的字段
awk命令后面跟操作的语句字符串''
包裹,每个语句段落用花括号{}
包裹,语句段落中用分号;
分隔语句。
echo -e '1 2 3\n4 5 6' |awk '{print $0;print("-end-")}'
echo -e '1 2 3\n4 5 6' |awk '{print $0;}{print("-end-")}'
#上面输出结果相同
#1 2 3
#-end-
#4 5 6
#-end-
echo -e '1 2 3\n4 5 6' |awk '{print $1,$3}'
#输出
#1 3
#4 6
使用内置变量
NF
表示当前行有多少个分割字段
echo '1-2-3' |awk -F '-' '{print $(NF)}' # 3 获取最后一个分割字符
echo '1-2-3' |awk -F '-' '{print $(NF-1)}' # 2 获取倒数第二个分割字符
其他变量
NR
表示当前处理的是第几行
BEGIN预处理
在执行处理之前提前设置一些信息
比如之前的-F
参数可以使用BEGIN来设置
echo -e "a-b-c" |awk 'BEGIN{FS="-"} /^a/{print $0}' #设置分割符为-
echo -e "a-b-c" |awk 'BEGIN{FS="-";print "this title::"} {print $0}' #设置输出的首行标题
echo -e "1122\n3344" |awk 'BEGIN{FIELDWIDTHS="2 2";} {print $1,$2}' #固定字段宽度 (mac os中测试失败)
#输出
#11 22
#33 44
内置变量
FS字段分隔符
FIELDWIDTHS指定字段宽度
ORS指定输出的行分隔符
if逻辑处理
awk还可以支持函数和复杂的逻辑处理,完全可以在里面定义函数 调用 判断
例子:
显示红色error
绿色seccess
白色log
echo -e 'success\nerror\nsuccess\nloginfo' | awk \
'{
if (/error/) {
print "\033[91m" $0 "\033[0m"
} else if (/success/){
print "\033[32m" $0 "\033[0m";
}else{
print $0
}
next;
}'
上面语句有换行的段落方便阅览。一行简写也是可以
例子:
判断值大小
echo -e '12\n14\n232\n90' |awk '{if($0>=90) print $0}' #输出>=90的数据
#232
#90
for循环
使用for循环计算求和
echo '5' |awk '{ \
total = 0
for (var = 1; var < $0; var++)
{
total += var
}
print "total:",total
}'
Built-In Functions函数使用
awk中语义中支持函数的使用
echo -e 'H htjim\nDot\ncom\n009' |awk '{print toupper($0)}'#转换为大写
内置函数
toupper 转换为大写
tolower 转换为小写
rand 随机数
其他函数参考手册:
https://www.gnu.org/software/gawk/manual/html_node/Built_002din.html#Built_002din
自定义函数
自定义彩色文字输出函数awk内部执行调用
echo -e 'success\nerror\nsuccess\nloginfo' | awk \
'
function red(s) {
printf "\033[1;31m" s "\033[0m "
}
function green(s) {
printf "\033[1;32m" s "\033[0m "
}
function blue(s) {
printf "\033[1;34m" s "\033[0m "
}
{
if (/error/) {
print red($0)
} else if (/success/){
print green($0)
}else{
print blue($0)
}
}'
其他例子
结合tail -f log
显示红色报错提示
tail -f test.log | awk '{
if (/success/) {
print "\033[91m" $0 "\033[0m"
} else {
print "\033[32m" $0 "\033[0m";
}
next;
}';
next
用于直接跳到下一行文本进行执行 有点continue
的意思
参考:
https://likegeeks.com/awk-command/
http://www.ruanyifeng.com/blog/2018/11/awk.html
https://www.cnblogs.com/Linuxprobe/p/5745381.html