python异步和多线程_Python 异步 IO(asyncio)、多进程、多线程性能对比

IO 密集型应用

IO 密集型应用CPU等待IO时间远大于CPU 自身运行时间,太浪费;常见的 IO 密集型业务包括:浏览器交互、磁盘请求、网络爬虫、数据库请求等

cac56b3d9a18

image.png

Python 世界对于 IO 密集型场景的并发提升有 3 种方法:多进程、多线程、异步 IO(asyncio);理论上讲asyncio是性能最高的,原因如下:

1.进程、线程会有CPU上下文切换

2.进程、线程需要内核态和用户态的交互,性能开销大;而协程对内核透明的,只在用户态运行

3.进程、线程并不可以无限创建,最佳实践一般是 CPU*2;而协程并发能力强,并发上限理论上取决于操作系统IO多路复用(Linux下是 epoll)可注册的文件描述符的极限

那asyncio的实际表现是否如理论上那么强,到底强多少呢?我构建了如下测试场景:

访问500台 DB,并sleep 100ms模拟业务查询

方法 1;顺序串行一台台执行

方法 2:多进程

方法 3:多线程

方法 4:asyncio

方法 5:asyncio+uvloop

最后的asyncio+uvloop和官方asyncio 最大不同是用 Cython+libuv 重新实现了asyncio 的事件循环(event loop)部分,官方测试性能是 node.js的 2 倍,持平 golang。

以下测试代码需要 Pyhton3.7+:

顺序串行一台台执行

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

import records

user=xx

pass=xx

port=xx

hosts= [....] # 500台 db列表

def query(host):

conn = records.Database(

f'mysql+pymysql://{user}:{pass}@{host}:{port}/mysql?charset=utf8mb4')

rows = conn.query('select sleep(0.1);')

print(rows[0])

def main():

for h in hosts:

query(h)

# main entrance

if __name__ == '__main__':

main()

多进程

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

from concurrent import futures

import records

user=xx

pass=xx

port=xx

hosts= [....] # 500台 db列表

def query(host):

conn = records.Database(

f'mysql+pymysql://{user}:{pass}@{host}:{port}/mysql?charset=utf8mb4')

rows = conn.query('select sleep(0.1);')

print(rows[0])

def main():

with futures.ProcessPoolExecutor() as executor:

for future in executor.map(query,hosts):

pass

# main entrance

if __name__ == '__main__':

main()

多线程

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

from concurrent import futures

import records

user=xx

pass=xx

port=xx

hosts= [....] # 500台 db列表

def query(host):

conn = records.Database(

f'mysql+pymysql://{user}:{pass}@{host}:{port}/mysql?charset=utf8mb4')

rows = conn.query('select sleep(0.1);')

print(rows[0])

def main():

with futures.ThreadPoolExecutor() as executor:

for future in executor.map(query,hosts):

pass

# main entrance

if __name__ == '__main__':

main()

asyncio

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

import asyncio

from databases import Database

user=xx

pass=xx

port=xx

hosts= [....] # 500台 db列表

async def query(host):

DATABASE_URL = f'mysql+pymysql://{user}:{pass}@{host}:{port}/mysql?charset=utf8mb4'

async with Database(DATABASE_URL) as database:

query = 'select sleep(0.1);'

rows = await database.fetch_all(query=query)

print(rows[0])

async def main():

tasks = [asyncio.create_task(query(host)) for host in hosts]

await asyncio.gather(*tasks)

# main entrance

if __name__ == '__main__':

asyncio.run(main())

asyncio+uvloop

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

import asyncio

import uvloop

from databases import Database

user=xx

pass=xx

port=xx

hosts= [....] # 500台 db列表

async def query(host):

DATABASE_URL = f'mysql+pymysql://{user}:{pass}@{host}:{port}/mysql?charset=utf8mb4'

async with Database(DATABASE_URL) as database:

query = 'select sleep(0.1);'

rows = await database.fetch_all(query=query)

print(rows[0])

async def main():

tasks = [asyncio.create_task(query(host)) for host in hosts]

await asyncio.gather(*tasks)

# main entrance

if __name__ == '__main__':

uvloop.install()

asyncio.run(main())

运行时间对比

方式

运行时间

串行

1m7.745s

多进程

2.932s

多线程

4.813s

asyncio

1.068s

asyncio+uvloop

0.750s

可以看出: 无论多进程、多进程还是asyncio都能大幅提升IO 密集型场景下的并发,但asyncio+uvloop性能最高,运行时间只有原始串行运行时间的 1/90,相差快 2 个数量级了!

内存占用对比

串行

cac56b3d9a18

image.png

多进程

cac56b3d9a18

image.png

多线程

cac56b3d9a18

image.png

asyncio

cac56b3d9a18

image.png

asyncio+uvloop

cac56b3d9a18

image.png

可以看出asyncio+uvloop内存占用表现仍然最优,只有 60M;而多进程占用多达 1.4G,果然创建进程是个十分重的操作~

总结

asyncio 无论运行时间还是内存占用都远优于多进程、多线程,配合 uvloop 性能还能进一步提升,在 IO 密集型业务中可以优先使用 asyncio。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 库是否可行? 可以回答这个问题。Python 多线程调用异步库是可行的,但需要注意线程安全问题。异步库本身是为了解决 I/O 密集型任务而设计的,多线程可以提高 CPU 密集型任务的效率,但需要注意避免多线程之间的资源竞争和死锁等问题。建议使用 Python 的协程库 asyncio 来实现异步编程,同时使用 threading 或 multiprocessing 来实现多线程多进程。 ### 回答2: Python中可以通过多线程调用异步操作来提高程序的并发能力和响应速度。 在Python中,可以使用`threading`模块来创建和管理多线程多线程是一种并发执行的方式,它允许多个线程在同一时间内执行不同的任务。 同时,Python也支持异步编程,可以通过`asyncio`模块来进行异步操作。异步操作可以在等待某些IO操作完成时,让出CPU资源给其他任务,以提高效率。 我们可以将异步操作放在一个线程中进行执行。具体步骤如下: 1. 使用`threading`模块创建一个线程对象,并指定一个函数为线程的执行体。 2. 在该函数中,使用`asyncio`模块的相关方法来定义和执行异步操作,比如使用`async`关键字定义异步函数,使用`await`关键字阻塞等待异步操作的完成。 3. 启动线程,开始执行异步操作。 这样,我们就可以在一个线程中同时执行多个异步操作,提高程序的并发能力。 需要注意的是,由于Python的全局解释锁(GIL)的存在,使得多线程无法真正实现并行执行。因此,通过多线程调用异步来提高程序的性能,主要是通过异步操作的非阻塞特性来实现任务的并发执行,而不是真正的并行执行。 总结起来,Python通过多线程调用异步可以提高程序的并发能力和响应速度,但需要注意多线程无法真正实现并行执行的限制。 ### 回答3: Python中的多线程调用异步可以通过一些库和技巧来实现。 首先,要注意Python的全局解释器锁(GIL),它会限制同一时间只能有一个线程在解释器中执行Python字节码。因此,Python多线程并不能真正实现并行计算,但可以用于处理I/O密集型任务。 要在Python中实现多线程调用异步,可以使用以下的方式之一: 1. asyncio库:asyncioPython异步I/O框架,它使用协程来实现异步编程。可以使用asyncio库在多个线程中调用异步函数。需要注意的是,在使用asyncio时,应该确保所有的I/O操作都是非阻塞的,否则会阻塞主线程。 2. 多进程 + 异步库:Python中也可以通过多进程来实现并行的异步编程。可以使用multiprocessing库来创建多个进程,然后在每个进程中使用异步库来处理异步任务。 3. 线程池 + 异步库:Python中的concurrent.futures库提供了线程池和进程池的实现,可以通过线程池来实现多线程调用异步。可以使用ThreadPoolExecutor类来创建线程池,并将异步任务提交给线程池处理。 无论采用哪种方式,多线程调用异步都需要注意线程安全和资源共享的问题。需要使用锁和同步机制来保证线程安全,并避免竞态条件和死锁的发生。 综上所述,Python多线程调用异步可以使用asyncio库、多进程异步库、线程池和异步库等方式实现。具体选择哪种方式取决于实际需求和场景。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值