社区首页 >问答首页 >在python asyncio.Task中直到主任务完成后才引发异常

这是代码,我认为程序会立即崩溃,因为这是不寻常的例外。然而,当主要任务coro2完成时,它等待了10秒。

代码语言:javascript
代码运行次数:0
复制
import asyncio

@asyncio.coroutine
def coro1():
    print("coro1 primed")
    yield
    raise Exception("abc")

@asyncio.coroutine
def coro2(loop):
    try:
        print("coro2 primed")
        ts = [asyncio.Task(coro1(),loop=loop) for _ in range(2)]
        res = yield from asyncio.sleep(10)
        print(res)
    except Exception as e:
        print(e)
        raise

loop= asyncio.get_event_loop()
loop.run_until_complete(coro2(loop))

我认为这是一个严重的问题,因为在更复杂的程序中,这会使进程永远停滞不前,而不是因为异常信息而崩溃。

此外,我在except块中在run_until_complete源代码中设置了一个断点,但没有触发。我感兴趣的是哪个代码在python异步中处理了该异常。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-12-19 05:07:08

首先,没有理由在Python中使用具有多年来可用的异步/等待语法的基于生成器的协同器,而coroutine装饰器现在已不再推荐并计划删除。另外,您不需要将事件循环向下传递到每个协同线,您可以在需要时使用asyncio.get_event_loop()来获得它。但这些和你的问题无关。

except块在coro2中没有触发,因为在coro1中引发的异常没有传播到coro2。这是因为您显式地将coro1作为一个任务运行,它在后台执行它,而不是等待它。您应该始终确保您的任务被等待,然后异常不会被忽略;系统地这样做有时被称为结构化并发

编写以上内容的正确方法如下:

代码语言:javascript
代码运行次数:0
复制
async def coro1():
    print("coro1 primed")
    await asyncio.sleep(0)  # yield to the event loop
    raise Exception("abc")

async def coro2():
    try:
        print("coro2 primed")
        ts = [asyncio.create_task(coro1()) for _ in range(2)]
        await asyncio.sleep(10)
        # ensure we pick up results of the tasks that we've started
        for t in ts:
            await t
        print(res)
    except Exception as e:
        print(e)
        raise

asyncio.run(coro2())

请注意,这将运行sleep()直到完成,然后才会传播由后台任务引发的异常。如果您想立即进行传播,可以使用asyncio.gather(),在这种情况下,您首先不必费心显式地创建任务:

代码语言:javascript
代码运行次数:0
复制
async def coro2():
    try:
        print("coro2 primed")
        res, *ignored = await asyncio.gather(
            asyncio.sleep(10),
            *[(coro1()) for _ in range(2)]
        )
        print(res)
    except Exception as e:
        print(e)
        raise

我感兴趣的是哪个代码在python异步中处理了该异常。

由coroutine引发的未被处理的异常被异步捕获并存储在任务对象中。这允许您等待任务,或者(如果您知道任务已经完成)使用result()方法获得其结果,其中任一方法将传播(重新引发)异常。由于您的代码从未访问任务的结果,因此异常实例在任务对象中仍然被遗忘。Python注意到了这一点,并在任务对象被销毁时打印了一个“任务异常从未检索过”警告,但是这个警告是在尽力而为的基础上提供的,通常来得太晚,不应该依赖。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65369022

复制
相关文章
Qt高并发
QThread是一个低级(low-level)类,适合用于显式地构建长期运行的线程。
全栈程序员站长
2022/09/03
1.5K0
【Qt】Qt的线程(两种QThread类的详细使用方式)「建议收藏」
Qt提供QThread类以进行多任务处理。与多任务处理一样,Qt提供的线程可以做到单个线程做不到的事情。例如,网络应用程序中,可以使用线程处理多种连接器。
全栈程序员站长
2022/09/01
10K0
Qt多线程编程之线程池
线程的创建及销毁需要与系统交互,会产生很大的开销。若需要频繁的创建线程建议使用线程池,有线程池维护一定数量的线程,当需要进行多线程运算时将运算函数传递给线程池即可。线程池会根据可用线程进行任务安排。
DeROy
2020/09/10
4.2K0
Qt多线程编程之线程池
QThread的用法
QThread类提供了一个与平台无关的管理线程的方法。一个QThread对象管理一个线程。QThread的执行从run()函数的执行开始,在Qt自带的QThread类中,run()函数通过调用exec()函数来启动事件循环机制,并且在线程内部处理Qt的事件。在Qt中建立线程的主要目的就是为了用线程来处理那些耗时的后台操作,从而让主界面能及时响应用户的请求操作。QThread的使用方法有如下两种:
全栈程序员站长
2022/07/21
9130
QThread的用法
QT学习之如何使用Qthread(moveToThread方法)
通常在程序中需要同时做好几件事情,这时不可避免的会涉及到多线程的学习,QT学习过程中亦是如此,而QT中提供了 QThread,因为涉及到信号与槽,线程的使用也有些变化。在QThread的文档中有两种使用方法。
嵌入式小屋
2022/04/27
4.9K0
QT学习之如何使用Qthread(moveToThread方法)
qtcpsocket多线程_qtcpsocket接收数据
最近在写有关网络传输的项目,使用了Qt封装的QTcpSocket,但是发现很多的跨线程导致死机的问题,也许是我了解的不够深入吧。最开始是自己继承一个线程然后把主线程创建的套接字传递到子线程并且在子线程中写入数据遇到程序崩溃;否决后是考虑到了跨线程访问的问题,QTcpSocket跨线程崩溃说明它只能是在哪个线程创建就只能在哪个线程使用,这样想的话只需要把特别耗时的处理(数据准备操作)放到一个子线程中,然后把待写入数据通过信号槽的形式传递给QTcpSocket所在线程(其实就是主线程)中然后调用QTcpSocket::write()发送,但是这就让主线程在写数据了,如果数据不是很大倒也可以,看个人情况而定;最后决定使用QObject::moveToThread()的方式,因为我要不间断的发送大量的数据所以在一个子线程中操作才是明智的选择,就是把在主线程创建好的QTcpSocket对象通过QObject::moveToThread()放到一个子线程中操作(也就相当于是在子线程创建的),后续的QTcpSocket与主线程之间的操作都是通过信号槽形式进行的。
全栈程序员站长
2022/09/30
1.2K0
qtcpsocket多线程_qtcpsocket接收数据
QObject
说到Qt,你肯定首先想到的就是信号和槽,而这就不得不提到Qobject,这次和大家分享下QObject的相关内容,并对一些内容进行代码说明,方便理解。
用户5908113
2019/12/19
1.2K0
QObject
简化QThread示例代码
QThread官方文档在描述线程内容时,提供了一个线程操作的方法,该方法用在大部分场景下都可以适用,但使用起来略有繁琐,需要创建一个线程执行类Worker和控制类Controller,如下代码:
Qt君
2023/03/17
5640
简化QThread示例代码
Qt多线程编程
我在github仓库里面看到之前遗留的Qt_Demo,把文章相应的工程文件提交到仓库里面去,上次的简易聊天室也同步过去了,以及这篇文章的两个线程Demo。
DeROy
2020/09/01
2.2K0
Qt多线程编程
qt多线程编程实例_lgbt
每个程序启动后拥有的第一个线程称为主线程,即GUI线程。QT中所有的组件类和几个相关的类只能工作在GUI线程,不能工作在次线程,次线程即工作线程,主要负责处理GUI线程卸下的工作。
全栈程序员站长
2022/08/18
1.5K0
Qt线程使用的两种方法
一个QThread实例管理程序中的一个线程。QThread的执行开始于run()。默认情况下,run()通过调用exec()启动事件循环,并在线程内运行Qt事件循环。   你可以使用QObject::moveToThread()将工作对象移动到线程中使用。
Qt君
2019/07/15
2.8K0
QThread 的使用「建议收藏」
注意看倒数第二个单词,QThread 不等于线程,QThread 是负责管理线程的。 接下来看文档,我们清楚的知道QThread的两种使用方式。
全栈程序员站长
2022/09/01
1.5K0
Qt多线程1:QThread
Qt有两种多线程的方法,其中一种是继承QThread的run函数,另外一种是把一个继承于QObject的类转移到一个Thread里。 Qt4.8之前都是使用继承QThread的run这种方法,但是Qt4.8之后,Qt官方建议使用第二种方法。两种方法区别不大,用起来都比较方便,但继承QObject的方法更加灵活。这里要记录的是如何正确的创建一个线程,特别是如何正确的退出一个线程。
全栈程序员站长
2022/09/02
2.9K0
Qt 线程中使用socket(勘误)
之前写过两篇关于qt线程中使用socket的文章,昨天有小伙伴看了文章之后和我讨论,然后我发现有一篇文章有问题,今天特地更正一下,误导了之前的小伙伴表示歉意。
用户5908113
2019/09/09
1.5K0
Qt 线程中使用socket(勘误)
Qt线程中使用socket作为客户端通信(二)
Qt使用线程的方式有两种,一种是上次所说的继承QThread重新实现run()函数,在run()函数中一直循环处理;另一种则是继承QObject并使用moveToThread()函数将对象移到子线程中。由于继承QThread方式使用的并不规范,Qt官方强烈建议使用继承QObject的方式。
用户5908113
2019/07/29
3.1K0
QT多线程实战_Qt多线程开发项目
窗口本身就是一个死循环,在这样一个死循环中执行任何耗时的操作,都会导致程序崩溃。所以多线程对于窗口编程而言是必要的。
全栈程序员站长
2022/11/16
1.4K0
QT多线程实战_Qt多线程开发项目
你这样做是错的…(翻译文)
我们广泛使用IRC(网上交谈)与我们自己以及社区进行沟通。我在Freenode网络的Qt频道上闲逛,尽我所能帮助别人。
Qt君
2019/08/20
8610
qt tcpsocket_qt中udp通信
设想有如下场景:若干的客户端与服务器端建立连接,建立连接后,服务器端随机发送字符串给客户端,客户端打印输出。该节案例使用TCP编程。
全栈程序员站长
2022/09/30
9010
【Pyside6】Python多线程实现的选择与QThread的推荐实现方式
因为在网络上,特别是中文互联网上,关于Pyside6多线程的写法,特别是QThread的使用提及比较少,且较多使用不太推荐的写法,这篇博客主要是存下我自己参考的博客,希望对大家也有帮助。
Livinfly
2023/03/16
4.8K0
【Pyside6】Python多线程实现的选择与QThread的推荐实现方式
qtcpsocket断开_2020-05-06 QT子线程使用QTcpSocket连接服务器
分别是:1.继承QThread实现多线程2.继承QObject实现多线程(由于继承QObject的多线程实现方法更加灵活,Qt官方推荐使用该方法实现多线程)。这里将采用第二种方式实现多线程
全栈程序员站长
2022/10/03
1.5K0

相似问题

QObject::moveToThread并在线程内执行成员函数

21

QObject::moveToThread中的移动语义

36

如何在Qt5中检测QObject::moveToThread()失败?

22

带有自定义Qobject的MovetoThread问题

26

如何在使用moveToThread时在PyQt5中正确退出moveToThread

155
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文