- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
默认情况下,asyncio
同步运行协程。如果它们包含阻塞的IO代码,则它们仍然等待其返回。解决方法是 loop.run_in_executor()
,它将代码转换为线程。如果某个线程在IO上阻塞,则另一个线程可以开始执行。这样您就不会浪费时间等待IO调用。
如果您在没有执行程序的情况下使用asyncio
,则会失去这些加速。所以我想知道,为什么您必须显式使用执行程序。为什么不默认启用它们?
(在下文中,我将重点介绍http请求。但是,它们实际上仅作为示例。我对一般原则感兴趣。)
经过一番搜索,我发现aiohttp。这是一个实质上提供asyncio
和requests
组合的库:非阻塞HTTP调用。对于执行程序,asyncio
和requests
的行为几乎类似于aiohttp
。有没有实现新库的理由,您是否因使用执行程序而支付性能损失?
回答了这个问题:Why doesn't asyncio always use executors?
Mikhail Gerasimov向我解释说,执行程序将加速OS线程,并且它们可能变得昂贵。因此,不要将它们作为默认行为是有道理的。 aiohttp
比在执行程序中使用requests
模块更好,因为它仅提供协程提供非阻塞代码。
这使我想到了这个问题。 aiohttp广告自己为:
Asynchronous HTTP Client/Server for asyncio and Python.
aiohttp
是基于
asyncio
的?那么
asyncio
为什么不只提供协程提供非阻塞代码呢?那将是理想的默认值。
aiohttp
本身实现了这个新的事件循环(没有OS线程)?
asyncio
做广告。
Async/await
是一种语言功能。
Asyncio
是一个事件循环。而且,如果
aiohttp
有其自己的事件循环,则应该与
asyncio
几乎没有交集。实际上,我认为这样的事件循环将比http请求具有更大的功能。
最佳答案
asyncio
是异步的,因为协程是自愿合作的。 在编写所有 asyncio
代码时必须牢记合作,这就是重点。否则,您也可以单独使用线程来实现并发。
您不能在执行程序中运行“阻塞”功能(非协程函数或无法配合使用的方法),因为您不能仅仅假设代码可以在单独的执行程序线程中运行。甚至即使它需要在执行程序中运行。
Python标准库中充满了非常有用的代码,asyncio
项目将要使用这些代码。标准库的大部分由常规的“阻止”功能和类定义组成。他们工作很快,所以即使他们“阻塞”,他们也会在合理的时间内返回。
但是大多数代码也不是线程安全的,通常不需要。但是,一旦asyncio
将自动在执行程序中运行所有此类代码,那么您将无法再使用非线程安全的函数。此外,创建线程以运行同步代码不是免费的,创建线程对象会花费时间,并且您的操作系统也不允许您运行无限数量的线程。标准库函数和方法的加载速度很快,为什么只执行代码并完成它会更快得多,为什么要在单独的线程中运行str.splitlines()
或urllib.parse.quote()
?
您可能会说这些功能并未受到您的标准的阻碍。您没有在此处定义“阻塞”,但“阻塞”仅表示:不会自动让步。如果将其缩小为在必须等待某件事并且计算机可能正在做其他事情时不会自动让步相反,接下来的问题将是您如何检测应该产生的?
答案是,你做不到。 time.sleep()
是您要屈服于循环的阻塞函数,但这是C函数的调用。 Python无法知道time.sleep()
将阻塞更长的时间,因为调用time.sleep()
的函数将在全局命名空间中查找名称time
,然后在名称查找结果中查找属性sleep
,仅在实际执行time.sleep()
时表达。由于在执行过程中可以随时更改Python的 namespace ,因此,在实际执行函数之前,您不知道time.sleep()
将做什么。
您可以说time.sleep()
实现应在调用时自动产生,但随后您必须开始标识所有此类函数。而且,您不必打补丁的地方数量也没有限制,而且您永远不可能知道所有地方。当然不适合第三方库。例如, python-adb
project使用libusb1
库为您提供了与Android设备的同步USB连接。那不是标准的I/O代码路径,那么Python怎么会知道创建和使用这些连接是产生 yield 的好地方?
因此,您不能仅假设代码需要在执行程序中运行,并非所有代码都可以在执行程序中运行,因为它不是线程安全的,并且Python无法检测到何时代码被阻塞并且应该真正产生。
那么asyncio
下的协程如何协作?通过每个需要与其他任务同时运行的逻辑代码使用task objects,并通过使用future objects向任务发信号通知当前逻辑代码希望将控制权让给其他任务。这就是使异步asyncio
代码异步,自愿让出控制的原因。当循环将控制权从一个任务中选出时,该任务将执行协程调用链的一个“步骤”,直到该调用链产生一个将来的对象,此时该任务将唤醒回调添加到将来的对象“完成” '回调列表,并将控制权返回到循环。在以后的某个时刻,当将来标记为完成时,将运行唤醒回调,并且该任务将执行另一个协程调用链步骤。
其他负责将将来的对象标记为已完成。当您使用asyncio.sleep()
时,将在特定时间运行的回调被赋予循环,该回调将把asyncio.sleep()
将来标记为完成。当您使用stream object执行I/O时(在UNIX上),循环将使用 select
calls来检测何时完成I/O操作时唤醒将来的对象。当您使用lock or other synchronisation primitive时,同步原语将在适当的时候维护一堆 future 以将其标记为“完成”(等待锁?将 future 添加到桩中。释放持有的锁?从桩中选择下一个 future 并将其标记为完成,因此等待锁的下一个任务可以唤醒并获取锁,依此类推)。
将阻塞的同步代码放入执行程序中只是这里合作的另一种形式。在项目中使用asyncio
时,开发人员应确保使用给定的工具来确保协程协同工作。您可以自由地在文件上使用阻塞open()
调用而不是使用流,并且当您知道需要在单独的线程中运行代码以避免阻塞时间太长时,可以自由使用执行程序。
最后但并非最不重要的一点是,使用asyncio
的全部目的是尽可能避免使用线程。使用线程有缺点。代码必须是线程安全的(控制可以在任何地方的线程之间切换,因此访问共享数据的两个线程应格外小心,“小心”可能意味着代码变慢了)。线程无论是否有事都要执行。在所有等待I/O发生的固定数量的线程之间切换控制会浪费CPU时间,其中asyncio
循环可自由查找未等待的任务。
关于python - 异步: why isn't it non-blocking by default,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53264314/
我已经盯着它看了好几个小时了,想不出解决办法;我通常使用正则表达式处理这种类型的验证,但我正在尝试使用内置解决方案进行更改(显然,我不经常这样做): private static double pro
有什么区别 grep -isn "String\.format" -R . 和 grep -isn String\.format -R . 当我使用后者时,结果包括String format和Stri
我有一部固件为 4.3 的 iPhone 3GS。我下载了 3.1.3 固件,并希望使用 Organizer 恢复 iPhone。但!我收到以下错误: “此设备不符合所请求的版本。” 知道出了什么问题
我创建了一个小界面: import ... abstract class IController { void navigateTo(BuildContext context, String ro
基础this Question我使用扩展方法在 dart 中创建了一个枚举: enum TagVisibility { public, shared, private, } extensi
我在 Play 商店中放置了一个应用程序,我的 friend 正在运行 4.1(Nexus 7),在尝试安装我的应用程序时收到以下消息:“您的设备与此版本不兼容”。这是为什么来的?请任何人帮助我。 M
我在 Play 商店中放置了一个应用程序,我的 friend 在两台设备上运行 4.0.3,在尝试安装我的应用程序时收到以下消息:“您的设备与此版本不兼容”。 一台设备允许安装,另一台不允许。我允许
#!/usr/bin/env perl use warnings; use 5.12.2; my $c = 'f'; # could be a number too if ( $c eq 'd' ||
我正在编写一个Cocoa应用程序,我想实现一个全局热键功能。我实现了 Waffle Software 的 ShortcutRecorder.framework,并向我的 xib 添加了一个 custo
当我在开发该应用程序时,我点击了“运行”,一旦应用程序启动,它就会在打开启动屏幕之前卡住,并向我显示“应用程序没有响应,您想关闭它吗” 对话。!! !我什至没有打开闪屏类。!我在 OnCreate 中
大约 12 小时前,我尝试使用“beautiful jekyll”创建个人博客。 '。我遵循最简单的三步方法来运行一个基本的博客,但是,每次我输入我的网站链接时,我都会得到 There isn't a
我正在解析制表符分隔的文件。有几列没有被识别为数字,即使它们显然是数字。当我尝试总结这些值时,会显示错误:Argument ""97""isn't numeric in addition (+) 并且
我有两个模型:posts 和 likings 它们具有一对多关系(因此,一个帖子有很多喜欢)。 Likings 模型还有一个 isActive 字段,它显示喜欢是主动的还是被动的。 我想获得(排序)获
我的 android 模拟器(没有 play store 的 api 30)不时显示这个错误对话框: 我点击“关闭应用程序”,屏幕瞬间变黑,然后一切恢复正常。 发生这种情况时,我会在 Logcat 中
我正在尝试使用 Electron 构建 Windows 和 Mac OS 应用程序,但遇到了障碍。 简而言之,如果我尝试在 Mac OS Big Sur 上直接使用 Electron 运行应用程序(而
use List::MoreUtils 'uniq'; print join ", ", sort uniq ("b", "a", "a"); 结果参数“a”在排序中不是数字... print joi
background: ShaderMask( shaderCallback: (rect) { return LinearGradient( begin: Ali
我正在尝试创建一个多项选择应用程序来计算正确和错误答案的数量。 一切都呈现良好,但应用程序无法正常工作: 用户的选择并不能定义为正确或错误的答案。 问题不会更改为下一个问题。 我好像在onClick(
我正在开发一个需要帐户链接的 Google 助理应用程序,我已经到了这样的步骤:如果我说“与 [我的应用程序名称] 交谈”,我会取回一张卡片带有文本“Link [my app name] to Goo
编译时出现以下错误: MenuNavigationApp.c:58: error: array type has incomplete element typeMenuNavigationApp.c:
我是一名优秀的程序员,十分优秀!