Python中如果一个程序需要进行大量的 IO 操作,应当使用并行还是并发?
null
Python中如果一个程序需要进行大量的 IO 操作,应当使用并行还是并发?
看具体业务
核心答案:用并发,特别是异步IO(asyncio)。
对于大量IO密集型任务,并发(特别是异步并发)是标准做法。并行(多进程)在这里是错误选择,原因很简单:
-
IO密集型 vs CPU密集型:
- IO密集型:程序大部分时间在等待(网络请求、文件读写、数据库查询)。此时CPU是空闲的。
- CPU密集型:程序大部分时间在进行计算(数据处理、图像渲染、复杂算法)。此时CPU是满的。
-
为什么不用并行(多进程):
- 创建进程开销大,消耗更多内存。
- 进程间切换成本高。
- 最关键的是:当某个进程在等待IO时,它占用的CPU核心就闲着,但操作系统调度器仍然把它当作一个需要调度的任务,这造成了资源浪费。开10个进程等网络响应,可能10个都在等,白占资源。
-
为什么用并发(特别是异步):
- 线程(并发):比进程轻量,但Python有GIL,对于纯IO任务,GIL影响不大,因为线程在IO时会释放GIL。但线程切换仍有开销,且编码需注意锁。
- 异步IO(asyncio):这是最推荐的方式。它使用单线程,通过事件循环在多个IO任务间快速切换。当一个任务发起IO请求后,立即让出控制权,事件循环去执行其他就绪的任务。IO完成时,事件循环再回来处理结果。这避免了线程/进程的创建和切换开销,能轻松管理成千上万的并发连接。
代码示例:异步IO(asyncio)处理大量HTTP请求
import asyncio
import aiohttp # 需要安装:pip install aiohttp
async def fetch_url(session, url):
"""异步获取单个URL的内容"""
try:
async with session.get(url, timeout=10) as response:
# 这里可以处理响应,例如读取文本
text = await response.text()
return f"{url}: 成功,长度 {len(text)}"
except Exception as e:
return f"{url}: 失败 - {e}"
async def main(urls):
"""主函数,并发获取所有URL"""
# 创建一个共享的aiohttp会话,比每个请求都创建会话更高效
async with aiohttp.ClientSession() as session:
# 为每个URL创建一个协程任务
tasks = [fetch_url(session, url) for url in urls]
# 并发运行所有任务,并等待它们全部完成
results = await asyncio.gather(*tasks)
# 输出结果
for result in results:
print(result)
if __name__ == "__main__":
# 示例URL列表
urls = [
"https://httpbin.org/delay/1", # 模拟延迟1秒的请求
"https://httpbin.org/delay/2",
"https://httpbin.org/delay/1",
"https://api.github.com",
"https://docs.python.org",
]
# 运行事件循环
asyncio.run(main(urls))
代码解释:
async def定义异步函数(协程)。await用于挂起当前协程,直到IO操作完成,期间事件循环可以执行其他任务。asyncio.gather()并发运行多个协程,并收集它们的结果。aiohttp.ClientSession()用于高效地发起HTTP请求。asyncio.run()启动事件循环。
总结建议:IO密集型任务直接用asyncio。
并行 /并发 有什么区别?
异步
并行:生产流水线
并发:购物订单
并行还是并发不看 IO,要看计算量大不大
揭秘 iPhone 售后的灰色产业链,是什么让苹果每年损失十多亿美元
https://zhuanlan.zhihu.com/p/46463952
「据外媒 The Information 统计,苹果在 2013 年用于全球售后维修的预算为 16 亿美元,但最终花了 37 亿美元来维持业务运营,而中国市场的售后处理占了业务支出的大头。」
楼上发错了 抱歉!
并行 /并发 是不是这么理解:
并行,多进程甚至多服务器
并发,单进程多线程
对于将来需要扩展的业务,显然必然选择多进程多服务器这种“分布式”,对于仅仅需要多几个线程充分用满当前 cpu,则并发多线程去运行
io 的瓶颈在于磁盘, 网卡等, 无法真正的并行, 即使调用上的并发量上去了, 效果也挺差的. 用异步的方式来解决, 降低消耗.
并行可类比为 2 个人同时去一台饮水机的两个出水口接水, 两个人一个要热水,一个要凉水, 并发类比两个人一起去都要热水
一张嘴同时说中午与英文是并行;说一句中午再说一句英文是并发。
这种咬文嚼字没有意义
erlang 解决烦劳
猜你实际上是想问密集 I/O 时 Python 用 多进程 or 多线程?
假若是问这个,两个都行啊。CPU 密集,则只得用多进程。
应当用 redis 等玩意
并发是指一次处理多件事。
并行是指一次做多件事。
二者不同,但是有联系。
一个关于结构,一个关于执行。
并发用于制定方案,用来解决可能(但未必)并行的问题。
– Rob Pike Go 语言的创造者之一
我自己想法是多线程+异步.
都可以
看情况
这两个冲突吗? 多进程+协程
看起来是 concurrency 和 parallel 的关系
我一直觉得并行是并发的一种方式
网络 IO 多开可能提速,硬盘 IO 能提速嘛?
反了吧
并发就是假的并行…
并行是指多核情况下同时处理多任务,并发是在单核下利用时间片来模拟同时处理多任务。
回答楼主问题。IO 密集型的程序使用多线程或线程并发即可,这种情况下能最大化利用 CPU。
这个应该使用并法逻辑流的 I/O 多路复用
这是啥问题?
并行和并发的定义是啥,不理解,能否补充一下英文关键词或者具体业务场景?
大量 IO 是指的磁盘 IO 还是网络 IO ?
异步加协程最好了
并发是场景,并行是方法,你怎么并发 IO ?
并行
我做过, 多线程+mmap
看情况 io 上限摆在那里 极限情况下并行并不能超过物理上限
反而因为大量上下文切换降低性能
你试试 多个大量数据的 SQL 文件并行插入 结果插入速度远低于顺序执行这些 sql 文件
但是多个少量 sql 文件 并行插入性能就不错
所以 看情况
中间层缓冲,统一 IO 进磁盘,随机 IO 真的废
是的😁


