什么时候不使用asyncio有意义? - python

在什么情况下会在asyncio上使用一个线程或执行程序(使用线程)?

随着我使用Python(CPython)的经验的进步,它集中于优化工作脚本以批量执行某种形式的Web服务调用并处理响应。但是,经过几代脚本构建之后,我发现自己想知道为什么我不使用最新的脚本?

请允许我在下面提供一些背景信息...

问题:从服务器A向客户端B请求N个文件,进行处理并将其保存到磁盘。

依序

构建请求的容器,发送单个请求,处理响应,重复直到完成
直觉上可以认为是“标准/初学者”方法

多线程

再次构建容器,但同时发送多个请求
使用信号量限制活动连接
使用队列在工作人员和转储响应之间共享
让主线程处理响应
从本质上讲,工作人员一劳永逸,并且主要运行在循环中,以检查队列中的数据
将关注点与主要处理数据的主要对象分开

线程池执行器

本质上与解决方案2相似,但是代码行少得多
推理:“我希望能够尽快处理回复”
不需要显式实例化Queue和Semaphore
如果没有记错的话,在as_completed()中使用Queue and Thread结构。
大致概述here

异步

在这里引起了严重的混乱,但是大多数人都理解概念
与解决方案2和3不同,在单个线程上运行
在实现中(非常)接近解决方案3,但写入磁盘除外
需要使用解决方案3组件通过run_in_executor()保存到磁盘

因此,我们陷入了当前的困境:为什么我永远不想使用asyncio进行I / O绑定工作?

异步编程是一个非常类似于OOP的概念,解决方案3的文档甚至说“可以使用线程执行异步执行”。但是,如果我可以在单个线程上实现异步执行(不包括用于阻止对磁盘的I / O的其他线程),为什么还要使用解决方案1-3?

我知道在GIL的情况下,CPython多线程是次优的;无论如何,我认为没有人会再使用线程或执行程序了。我做了很多谷歌搜索,看是否能找到一篇很好的文章,说明为什么人们更喜欢使用它们,但是我只发现了一些文章,说明线程(以及随后使用线程的执行者)为什么不好:上下文切换( GIL / OS),竞争条件,资源匮乏等...

由于CPython不使用线程来利用多个核心CPU(我相信multiprocessing库),因此线程不用于繁重的计算任务;因此,将它们限制在I / O限制的操作中以提高性能。但是,这并没有给我足够的理由来理解为什么在asyncio上使用线程或执行程序。

如果您可以在单个线程中(可能是2-3个)完成所有操作,为什么还要继续引入创建,管理和销毁线程的开销(无论是显式的还是通过池/执行器的)?

参考方案

我认为多线程和异步之间的决定确实取决于您需要哪种多任务。如果一切都在程序的控制之下,那么异步/多处理可能一直都是正确的选择。但是,也许您想开始一项任务,在此前提下,多任务处理是正确的选择。例如,您在第三方库中启动任务。使用线程的一个显而易见的原因是该库不支持异步。但是,即使它支持异步,您也许也不想信任该库来随心所欲地控制您的任务。然后,您可以使用另一个运行该代码的asyncio事件循环来启动新线程。

因此,我认为真正的问题是:何时使用协作以及何时使用抢占式多任务处理。

Python sqlite3数据库已锁定 - python

我在Windows上使用Python 3和sqlite3。我正在开发一个使用数据库存储联系人的小型应用程序。我注意到,如果应用程序被强制关闭(通过错误或通过任务管理器结束),则会收到sqlite3错误(sqlite3.OperationalError:数据库已锁定)。我想这是因为在应用程序关闭之前,我没有正确关闭数据库连接。我已经试过了: connectio…

Python:传递记录器是个好主意吗? - python

我的Web服务器的API日志如下:started started succeeded failed 那是同时收到的两个请求。很难说哪一个成功或失败。为了彼此分离请求,我为每个请求创建了一个随机数,并将其用作记录器的名称logger = logging.getLogger(random_number) 日志变成[111] started [222] start…

Python pytz时区函数返回的时区为9分钟 - python

由于某些原因,我无法从以下代码中找出原因:>>> from pytz import timezone >>> timezone('America/Chicago') 我得到:<DstTzInfo 'America/Chicago' LMT-1 day, 18:09:00 STD…

用大写字母拆分字符串,但忽略AAA Python Regex - python

我的正则表达式:vendor = "MyNameIsJoe. I'mWorkerInAAAinc." ven = re.split(r'(?<=[a-z])[A-Z]|[A-Z](?=[a-z])', vendor) 以大写字母分割字符串,例如:'我的名字是乔。 I'mWorkerInAAAinc”变成…

带后台线程的烧瓶应用程序 - python

我正在创建一个flask应用程序,对于一个请求,我需要运行一些长时间运行的作业,而无需在UI上等待。我将创建一个线程并将消息发送到UI。该线程将计算并更新数据库。但是,UI在提交后会看到一条消息。下面是我的实现,但是它正在运行线程,然后将输出发送到我不喜欢的UI。如何在后台运行此线程?@app.route('/someJob') def …