当前位置: 首页 > 知识库问答 >
问题:

asyncio模块是如何工作的,为什么更新后的示例会同步运行?

相弘方
2023-03-14

我已经尝试了Python 3.6中的asyncio的以下代码:示例1:

import asyncio
import time

async def hello():

    print('hello')
    await asyncio.sleep(1)
    print('hello again')

tasks=[hello(),hello()]    
loop=asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

产出如预期:

hello
hello
hello again
hello again

然后我想将asyncio.sleep更改为另一个def:

async def sleep():
    time.sleep(1)

async def hello():

    print('hello')
    await sleep()
    print('hello again')


tasks=[hello(),hello()]    
loop=asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

输出:

hello
hello again
hello
hello again

它似乎不是在异步模式下运行,而是在正常的同步模式下运行。

问题是:为什么它没有以异步模式运行,我如何将旧的同步模块更改为“异步”模块?

共有1个答案

易波涛
2023-03-14

Asyncio使用一个事件循环,它选择队列中接下来要激活的任务(一个独立的协同路由调用链)。事件循环可以做出关于什么任务准备好做实际工作的智能决策。这就是为什么事件循环还负责创建连接并监视文件描述符和其他I/O原语;它使事件循环能够洞察何时有正在进行的I/O操作或何时可以处理结果。

无论何时使用wait,都有机会将控制返回到循环,然后循环可以将控制传递给另一个任务。然后选择哪个任务执行取决于确切的实现;asyncio引用实现提供了多种选择,但是还有其他实现,例如非常非常高效的uvlink实现。

您的示例仍然是异步的。碰巧的是,通过使用同步的time.sleep()调用替换wait.sleep()调用,在一个新的协程函数中,您在任务调用链中引入了两个不产生的协程,从而影响了它们的执行顺序。它们似乎是以同步顺序执行的,这是一种巧合。如果您切换了事件循环,或者引入了更多的协程(特别是一些使用I/O的协程),那么顺序很容易再次不同。

此外,您的新协同程序使用time.sleep();这使得你的合作项目不合作。不会通知事件循环您的代码正在等待(time.sleep()将不会产生!),因此在运行time.sleep()时不能执行其他协同程序time.sleep()只是在请求的时间过去之前不返回或让任何其他代码运行。将此与asyncio.sleep()实现进行对比,后者通过call\u later()hook向事件循环屈服;事件循环现在知道该任务在以后才需要注意。

另请参见asyncio:why not is non blocking by default,以更深入地讨论任务和事件循环如何交互。如果必须运行无法使其协同工作的阻塞同步代码,则使用执行器池在单独的tread或子进程中执行阻塞代码,以便将事件循环释放给其他行为更好的任务。

 类似资料:
  • 本文向大家介绍react中的setState是同步还是异步的呢?为什么state并不一定会同步更新?相关面试题,主要包含被问及react中的setState是同步还是异步的呢?为什么state并不一定会同步更新?时的应答技巧和注意事项,需要的朋友参考一下 [react] react中的setState是同步还是异步的呢?为什么state并不一定会同步更新?

  • 问题内容: 我已经开始学习线程同步。 同步方法: 同步块: 什么时候应该使用方法和块? 为什么块比方法更好? 问题答案: 这不是更好的问题,只是有所不同。 同步方法时,实际上是在与对象本身进行同步。对于静态方法,您正在同步到对象的类。因此,以下两段代码以相同的方式执行: 就像您写的一样。 如果要控制到特定对象的同步,或者只想将方法的 一部分 同步到该对象,则指定一个块。如果在方法声明上使用关键字,

  • 这个练习直接来自SCJP,由凯西·塞拉和伯特·贝茨完成 同步代码块 在这个练习中,我们将尝试同步一个代码块。在该代码块中,我们将获得对象的锁,以便其他线程在代码块执行时无法修改它。我们将创建三个线程,它们都将尝试操作同一对象。每个线程将输出一个字母100次,然后将该字母递增一次。我们将使用的对象是StringBuffer。 我们可以在一个String对象上进行同步,但是字符串一旦创建就不能被修改,

  • 问题内容: 这是我的代码: 这是我的输出: 我的理解 是。因此,应该首先一个号码,然后松开,然后给到线或。所以,一次应该有一个数字,对吧? 但是为什么我的代码一次是两个或三个数字?我做错什么了吗(我是新手)? 问题答案: 虽然确实不是同步的,但是它访问变量。 即使您同步访问权限,它也无济于事,因为下一种情况仍然可能: 线程1增量 线程2增量 线程1的打印值 线程2的打印值 要解决此问题,您需要增加

  • 问题内容: 作为应用程序运行的一部分,我从远程数据库创建字典。这个过程相当I / O繁重,因此我决定创建此字典的“单例”实例,并根据需要在应用程序中对其进行调用。 代码看起来像(在中): 然后导入并在需要的地方调用该函数。我添加了一条打印语句,以检查是否正在重新初始化或重用,然后发现它已被重用(这是我想要的功能)。为什么幸存的应用程序实例运行? 编辑 我将功能导入多个文件。 问题答案: 这是《 P

  • 如果我有的话 在< code>b.py中,我可以< code >导入a 但如果我有 在<code>c中。pydo,突然出现在我得到 怎么了?我看不出第二种情况与第一种情况有什么不同 因此...在最初启动的模块的目录中搜索模块。我只是不明白其中的道理。 我不是在问如何解决问题。而是首先问为什么会有问题...... (在Python 3.8.8上测试)