如何使用Ctrl C优雅地关闭协同程序?

如何使用Ctrl C优雅地关闭协同程序?,第1张

概述我正在写蜘蛛来抓取网页.我知道asyncio可能是我最好的选择.所以我使用协同程序异步处理工作.现在我抓住了关于如何通过键盘中断退出程序的问题.所有工作完成后,该程序可能会关闭.源代码可以在python 3.5中运行,并在下面附上.import asyncio import aiohttp from contextlib import suppress c

我正在写蜘蛛来抓取网页.我知道asyncio可能是我最好的选择.所以我使用协同程序异步处理工作.现在我抓住了关于如何通过键盘中断退出程序的问题.所有工作完成后,该程序可能会关闭.源代码可以在python 3.5中运行,并在下面附上.

import asyncioimport aiohttpfrom contextlib import suppressclass SpIDer(object):    def __init__(self):        self.max_tasks = 2        self.task_queue = asyncio.Queue(self.max_tasks)        self.loop = asyncio.get_event_loop()        self.counter = 1    def close(self):        for w in self.workers:            w.cancel()    async def fetch(self,url):        try:            async with aiohttp.ClIEntSession(loop = self.loop) as self.session:                with aiohttp.Timeout(30,loop = self.session.loop):                    async with self.session.get(url) as resp:                        print('get response from url: %s' % url)        except:            pass        finally:            pass    async def work(self):        while True:            url = await self.task_queue.get()            await self.fetch(url)            self.task_queue.task_done()    def assign_work(self):        print('[*]assigning work...')        url = 'https://www.python.org/'        if self.counter > 10:            return 'done'        for _ in range(self.max_tasks):            self.counter += 1            self.task_queue.put_Nowait(url)    async def crawl(self):        self.workers = [self.loop.create_task(self.work()) for _ in range(self.max_tasks)]        while True:            if self.assign_work() == 'done':                break            await self.task_queue.join()        self.close()def main():    loop = asyncio.get_event_loop()    spIDer = SpIDer()    try:        loop.run_until_complete(spIDer.crawl())    except KeyboardInterrupt:        print ('Interrupt from keyboard')        spIDer.close()        pending  = asyncio.Task.all_tasks()        for w in pending:            w.cancel()            with suppress(asyncio.CancelledError):                loop.run_until_complete(w)    finally:        loop.stop()        loop.run_forever()        loop.close()if __name__ == '__main__':    main()

但如果我在运行时按“Ctrl C”,可能会出现一些奇怪的错误.我的意思是有时程序可以通过’Ctrl C’优雅地关闭.没有错误消息.但是,在某些情况下,程序将在按下“Ctrl C”后仍然运行,并且在完成所有工作之前不会停止.如果我在那一刻按下“Ctrl C”,“任务已被销毁,但它正在等待!”会在那里.

我已经阅读了一些关于asyncio的主题,并在main()中添加了一些代码来优雅地关闭协同程序.但它不起作用.别人有类似的问题吗?

最佳答案我打赌问题发生在这里:

except:    pass

你should never do这样的事情.而你的情况是另外一个例子.

取消任务并等待取消时,在任务内部引发asyncio.CancelledError,并在内部任何地方禁止shouldn’t be.您等待任务取消的行应该引发此异常,否则任务将继续执行.

这就是你这样做的原因

task.cancel()with suppress(asyncio.CancelledError):    loop.run_until_complete(task)  # this line should raise CancelledError,# otherwise task will continue

实际上取消任务.

UPD:

But I still hardly understand why the original code Could quit well by
‘Ctrl+C’ at a uncertain probability?

它依赖于你的任务状态:

>如果此时按“Ctrl C”,则所有任务都完成,而不是
它们会在等待时引发CancelledError,你的代码将正常完成.
>如果此时按“Ctrl C”某些任务正在等待,但接近完成执行,您的代码将在任务取消时停留一些,并在任务完成后立即完成.
>如果此时按“Ctrl C”,某些任务正在等待处理
远远没有完成,你的代码将卡住尝试取消这些任务(其中
无法做到).另一个’Ctrl C’将中断进程
取消,但任务不会被取消或完成然后你会得到
警告’任务已被破坏,但它正在等待!’. 总结

以上是内存溢出为你收集整理的如何使用Ctrl C优雅地关闭协同程序?全部内容,希望文章能够帮你解决如何使用Ctrl C优雅地关闭协同程序?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1206093.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-04
下一篇 2022-06-04

发表评论

登录后才能评论

评论列表(0条)

保存