Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
根据条件关闭Python中的任务_Python_Python 3.x_Websocket_Python Asyncio - Fatal编程技术网

根据条件关闭Python中的任务

根据条件关闭Python中的任务,python,python-3.x,websocket,python-asyncio,Python,Python 3.x,Websocket,Python Asyncio,我使用AsyncIO和websocket模块在Python中创建两个并发任务,每个任务连接到websocket服务器并接收消息 我正在尝试创建一个系统,当一个任务在超过4秒的时间内没有收到消息时,它必须关闭连接和任务,但我很难弄清楚这一点。有人能帮我吗 以下是我尝试过的: async def connect(URI): async with websockets.client.connect(URI) as ws: LastUpdate = time.time()

我使用AsyncIO和websocket模块在Python中创建两个并发任务,每个任务连接到websocket服务器并接收消息

我正在尝试创建一个系统,当一个任务在超过4秒的时间内没有收到消息时,它必须关闭连接和任务,但我很难弄清楚这一点。有人能帮我吗

以下是我尝试过的:

async def connect(URI):
    async with websockets.client.connect(URI) as ws:
        LastUpdate = time.time()
        while time.time() - LastUpdate < 4:
            LastUpdate = time.time()
            await ws.recv()

        print('Not receiving updates anymore')
                
async def main():
    Tasks = [asyncio.create_task(connect('URI1')), asyncio.create_task(connect('URI2'))]

    await asyncio.gather(*Tasks)

这里,main创建两个并发任务并同时运行这两个任务。connect负责连接和接收消息。我试图做的是在上次更新时间超过4秒时中断while循环,但由于循环没有中断,因此没有成功。

有几种方法可以做到这一点

您可以在异步例程中使用的包中设置超时。 您可以使用asyncio并在任务达到超时时终止任务。 您可以对所有操作使用非阻塞套接字,并且完全不使用asyncio,而是使用select或poll。这非常有效,但要复杂得多。 我会按照这个顺序去做,在大多数情况下,第一个是最容易和最受欢迎的。WebSocket似乎可以处理超时:

您可能需要在套接字上设置超时。一般来说,这是通过

我想WebSocket会在某个地方公开此功能,但我不熟悉它。

您可以使用:


URI1是这一行的输入错误吗?将websockets.client.connectURI1作为ws异步:是,已更正。非常感谢。按照倒数第二段所暗示的方式设置套接字超时将不起作用,因为OP使用的WebSocket不公开内部使用的套接字,而且还因为socket.settimeout只影响阻塞套接字。事实上,使用settimeout甚至会导致错误,因此不能与asyncio一起使用。关于3,使用非阻塞套接字和select/poll正是asyncio在内部所做的事情,因此asyncio超时应该与此一样有效。@user4815162342显然3指的是不使用asyncio的情况。但是你是对的,我可能应该补充一点,如果可能的话,设置套接字超时应该通过websockets库完成。我不熟悉它,但我认为,由于您可以通过套接字选项将套接字传递到wc.connect,因此应该手动完成。显然,3指的是不使用asyncio的情况-我理解,我只是指出,这种方法没有理由比一开始就使用asyncio更有效,因为它最终会在内核级别执行完全相同的操作。事实上,我认为根本不是这样。尽管我已经有几年没有研究过CPython解释器了,但上一次检查时,从Python对单个套接字执行此操作效率很低,每次都在单个套接字上调用select。您可以滚动自己的非阻塞套接字代码,并将其成批进行轮询/选择/等等。。。将始终更高效。这只是在你有数千个套接字的情况下才有意义,在这种情况下编写这样的代码相当困难,也不是很有用。事实上,我认为根本不是这样的-你应该检查asyncio的源代码,然后感到惊喜,因为它肯定会选择所有的文件描述符。这就是像asyncio这样的现代事件循环实现的全部要点,它的效率与自主开发的解决方案一样高(如果不是更高的话)。非常感谢您的回答!在这种情况下,我如何访问消息的内容?我试图将printawait ws.recv添加到您放置的“使用msg执行某些操作”的位置,但它给了我一个关于wait_的错误,因为它从未被等待过,所以访问消息ws.recv就可以了。至于错误,我认为问题在于它应该是msg=wait asyncio.wait\u forws.recv,4@JayK23内容本来应该放在局部变量msg中,但正如您所注意到的,我忘记在asyncio.wait_for前面放一个wait。我现在修改了答案,这很清楚。如果我希望我的代码在退出while循环后无限期地重试连接,我会怎么做?我目前使用更高级别的while循环来完成此操作,我将其放置在async def connect之后。。。这似乎有效,但我不知道是否有更好的方法。我知道这是不可能的,如果需要,我会再做一个。再次非常感谢@JayK23可能位于connect调用方的外部环路是一个合理的解决方案,是的。
async def connect(URI):
    async with websockets.client.connect(URI) as ws:
        while True:
            try:
                msg = await asyncio.wait_for(ws.recv(), 4)
            except asyncio.TimeoutError:
                break
            # do something with msg

        print('Not receiving updates anymore')