文章摘要
Python 3.4引入的asyncio库在3.5版本中成为正式标准,并引入了async和await关键字,推动了异步编程的发展。然而,asyncio存在诸多设计缺陷,使用复杂且难以掌握,甚至被认为在发布时就存在问题。相比之下,其他语言和库如Kotlin、Swift以及Python的Trio和AnyIO库在异步处理上表现更为优秀,修复了asyncio的许多问题。
文章总结
标题:asyncio:一个充满尖锐问题的库
主要内容:
Python 3.4(2014年发布)引入了一个新的标准库模块:asyncio,最初作为外部库tulip的导入,用于收集反馈。Python 3.5(2015年发布)中,async和await被添加为关键字,专门用于异步库,取代了yield from的用法。asyncio模块也在这次发布中正式成为标准库的一部分,标志着Python世界中异步库的新生态系统的诞生。
然而,asyncio存在许多设计问题和尖锐的角落,使得它难以使用,甚至可以说是从根本上存在缺陷。这些问题中的一些是在其他语言(如Kotlin、Swift)和库做得更好后才被意识到的;但大多数问题在发布时就已经存在,令人困惑的是,这个库是如何在存在如此明显缺陷的情况下脱离“临时”状态的。
本文提到了Trio库,它解决了asyncio中的许多问题。此外,AnyIO库在asyncio之上实现了类似Trio的语义,修复了本文描述的大多数问题,同时保留了与常规asyncio库的兼容性。
主要问题:
取消机制存在问题:
asyncio的取消机制是边缘触发的,而不是水平触发的。这意味着取消任务只会触发一次,而不是在所有事件循环调用中持续引发CancelledException。这导致在清理代码中,取消可能会被忽略或掩盖,从而导致死锁。任务被销毁但仍在挂起:
asyncio不会强引用任务,导致任务可能在执行过程中被垃圾回收,尤其是在使用wait_for、gather或shield等辅助函数时,任务可能会被意外丢弃。I/O存在无意义的陷阱:
asyncio的底层I/O API使用回调机制,而不是像Trio那样的线性控制流。这使得代码难以理解和维护,尤其是在处理复杂的协议时。asyncio.Queue难以使用:asyncio.Queue在处理生产者和消费者模式时存在背压问题,尤其是在消费者抛出异常时,生产者可能会无限期地阻塞或导致内存泄漏。
其他问题:
- 线程问题:
asyncio在处理线程时存在取消传播问题,取消任务不会取消同步任务运行的事件循环。 - 信号处理:
asyncio的信号处理API设计不佳,相比之下,Trio的open_signal_receiverAPI更为简洁和易用。 - 任务组:
asyncio的TaskGroup无法独立取消嵌套的任务组,而Trio的CancelScope可以独立取消任何嵌套的任务。
结论:
asyncio并不是一个设计良好的库,它充满了尖锐的问题和设计缺陷,导致用户不得不编写复杂的代码来规避这些问题。Trio几乎解决了本文提到的所有问题,而AnyIO则在asyncio之上实现了类似Trio的语义,同时保留了与asyncio库的兼容性。
评论总结
评论主要围绕Python的并发编程模型及其设计问题展开,观点多样且涉及多个方面:
Python并发模型的复杂性:
- 有评论指出,Python的并发模型(如asyncio)设计存在问题,甚至“近乎根本性缺陷”。(评论6:“asyncio has so many sharp corners and design issues [...] bordering on being fundamentally broken”)
- 另一评论提到,Python在处理并发时缺乏清晰的取消机制,线程只能自愿检查是否需要取消。(评论2:“The only solution is the one being complained about--for a thread to voluntarily check if it needs to be cancelled.”)
Python语言设计的争议:
- 有评论认为Python在项目初期表现良好,但随着项目进展,开发者往往希望用其他语言(如Java)重写。(评论3:“the real problem is python, great at the start of a project, by the end i am dying to rewrite in java.”)
- 另一评论指出,Python的设计存在“古怪”之处,导致其整体设计问题普遍存在。(评论4:“This seems like a microcosm of the general design problems that pervade Python.”)
对gevent的推崇:
- 有评论认为gevent是更好的并发解决方案,它通过猴子补丁实现了同步和并发代码的统一,避免了asyncio的复杂性。(评论5:“no async/await, instead every possible thing that could block in the standard library is monkey-patched to yield to an event loop”)
对asyncio的批评与替代方案:
- 有评论指出asyncio存在设计缺陷,建议使用anyio来弥补其不足。(评论7:“the key to using asyncio is to use anyio. Anyio is an interface that you can use ontop of asyncio and fixes most of its shortcomings.”)
- 另一评论则推崇Twisted,认为它比asyncio更有优势。(评论9:“Asyncio is too dull. Twisted for the win!”)
对取消机制的质疑:
- 有评论认为取消机制本身存在问题,类比“无法在中途取消小便”,质疑其合理性。(评论11:“Have you ever tried to cancel peeing mid-pee? It just doesn’t work.”)
对其他语言的比较:
- 有评论提到其他语言(如Erlang)在并发编程方面表现更好,暗示Python的并发实现可能只是对Erlang的拙劣模仿。(评论12:“Any sufficiently complicated concurrent program in another language contains an ad hoc informally-specified bug-ridden slow implementation of half of Erlang.”)
总结:评论中对Python的并发模型(尤其是asyncio)提出了诸多批评,认为其设计复杂且存在缺陷。同时,有评论推崇gevent和Twisted作为替代方案。此外,Python的整体语言设计也受到质疑,部分开发者认为其在项目后期表现不佳。