这是我代码的简化版本:
main
是在第二次迭代后停止的协程。get_numbers
是一个异步生成器,它在异步上下文管理器中生成数字。
import asyncio
class MyContextManager:
async def __aenter__(self):
print("Enter to the Context Manager...")
return self
async def __aexit__(self, exc_type, exc_value, exc_tb):
print(exc_type)
print("Exit from the Context Manager...")
await asyncio.sleep(1)
print("This line is not executed") # <-------------------
await asyncio.sleep(1)
async def get_numbers():
async with MyContextManager():
for i in range(30):
yield i
async def main():
async for i in get_numbers():
print(i)
if i == 1:
break
asyncio.run(main())
输出为:
Enter to the Context Manager...
0
1
<class 'asyncio.exceptions.CancelledError'>
Exit from the Context Manager...
其实我有两个问题:
\uuuaexit\uuuu0>中有一个await语句,那么该行后面的代码根本不会执行,我们不应该依赖它来清理,这是正确的吗
| aclose(...)
| aclose() -> raise GeneratorExit inside generator.
那么为什么我得到
*我正在使用Python 3.10.4
回答第一个问题:
如果我们在\uuaexit\uuuuu>中有一个await语句,那么该行后面的代码根本不会执行,这是正确的吗?
我会说不,情况并非总是如此。只要
main
有足够的时间并且可以再次将控制传递回事件循环,__aexit__
中的代码就可以执行。我尝试了这个:
async def main():
async for i in get_numbers():
print(i)
if i == 1:
break
await asyncio.sleep(4) # <---- New
<代码>。run()
只关心传递给它并最终运行的协同路由,而不关心其他协同路由,包括\uu aexit\uu。因此,如果它没有足够的时间或没有将控制传递给事件循环,我就不能依赖于第一个wait语句之后的下一行。
可能有助于的其他信息:
这里是base_events。py/run_forever
方法(由.run()调用),我发现了自己_asyncgen\u finalizer\u钩子传递给系统。设置异步钩子。asyncgen\u finalizer\u钩子的主体是:
def _asyncgen_finalizer_hook(self, agen):
self._asyncgens.discard(agen)
if not self.is_closed():
self.call_soon_threadsafe(self.create_task, agen.aclose())
但是call_soon_threadsafe
的实现是空的。
我稍后会清理这个答案并消除这些猜测。
答案很简单:解释器会在一秒钟后继续执行__aexit__
,但是main
函数完成了,没有指向上下文管理器的指针。
你提到的第一个明显的解决方案是在main函数之后等待足够长的时间:
async def main():
async for i in get_numbers():
print(i)
if i == 1:
break
await asyncio.sleep(4) # <---- New
另一种方法是使用try/finally:
async def __aexit__(self, exc_type, exc_value, exc_tb):
try:
pass
print(exc_type)
print("Exit from the Context Manager...")
await asyncio.sleep(1)
finally:
print("This line is not executed") # <-------------------
我不确定发生了什么,但发布我的发现,以防它被证明对决定调查的其他人有用。当我们将对get_numbers()
的引用存储在main()
之外时,输出会更改为预期。我会说get_numbers()
似乎是垃圾收集到早期,但是禁用gc
没有帮助,所以我的猜测可能是错误的。
import asyncio
test = None
class MyContextManager:
async def __aenter__(self):
print("Enter to the Context Manager...")
return self
async def __aexit__(self, exc_type, exc_value, exc_tb):
print(exc_type)
print("Exit from the Context Manager...")
await asyncio.sleep(1)
print("This line is not executed") # <-- Executed now
await asyncio.sleep(1)
async def get_numbers():
async with MyContextManager():
for i in range(30):
yield i
async def main():
global test
test = get_numbers()
async for i in test:
print(i)
if i == 1:
break
asyncio.run(main())
问题内容: 在Java 8中,我们有类,它奇怪地有一个方法 因此,您可能希望它实现接口,而该接口正是需要此方法,但事实并非如此。 当我想使用foreach循环遍历Stream时,我必须做类似的事情 我在这里想念什么吗? 问题答案: 人们已经在邮件列表 asked 上问过同样的问题。主要原因是Iterable也具有可重复的语义,而Stream没有。 我认为主要原因是Iterable暗示可重用性,而S
问题内容: 我是一名即将毕业的计算机科学专业的学生,在我的整个编码生涯中,我发现很少使用枚举的实例,除了典型的情况(例如代表标准纸牌的面孔)外,还使用了枚举。 您是否知道在日常编码中使用枚举的任何巧妙方法? 为什么枚举如此重要,在什么情况下应该能够确定建立枚举是最佳方法? 问题答案: 这些是主要的论点,以及短的例子。 的情况 从Java 6开始,是一个凌乱类的示例,该类可以从使用中受益匪浅(除
Bootstrapping(引导) 是 Netty 中配置程序的过程,当你需要连接客户端或服务器绑定指定端口时需要使用 Bootstrapping。 如前面所述,Bootstrapping 有两种类型,一种是用于客户端的Bootstrap,一种是用于服务端的ServerBootstrap。不管程序使用哪种协议,无论是创建一个客户端还是服务器都需要使用“引导”。 面向连接 vs. 无连接 请记住,这
问题内容: 在我的Web应用程序中,我在Apache Tomcat(TomEE)/7.0.37服务器上使用OpenJPA。我使用Netbeans自动生成类(“来自数据库的实体类…”和“来自实体类的会话Bean …”)。在SessionBean(例如UserFacade)上,我想获取EntityManager: 但是当我通过上述方式得到它时,我得到的是空值。当我通过: ecm不为空,还可以 我的pe
问题内容: 我有Ubuntu 10.10和apache2,php 5.3.3-1和mysql 5.1。 我正在通过URL向页面传递一些值。在该页面上,如果我这样做了,那么我会看到数组的内容。但是,如果我这样做数组是空的。任何想法为什么会这样? 问题答案: 也可以尝试检查php.ini中的“ request_order” 选项:
我的问题是无法使用和获取文本字段。我尝试使用XPath来选择对象,但没有成功。 这是我的代码: 我重新提出这个问题是因为旧的问题有点让人困惑,我想。这是旧的 XML形式的我的文档(Document.getXML()) 我需要选择文本字段,做一个邮件合并,我的计划将是复制和移动字段。如果有更好的方法,我愿意尝试一下:)