如何确保仅存在一个特定类型的协程

在我的课堂上,我有一个获取网站的方法(如下所示)。


我注意到使用此方法的其他方法可能会导致向一个站点打开多个请求(当一个请求待处理时 self._page 仍然没有)。


我怎样才能避免它?


我的意思是,当有另一个对 _get_page 的调用但有一个正在等待时,只需从第一个调用返回一个 future 并且不要重复页面请求


async def _get_page(self) -> HtmlElement:

        if self._page is None:

            async with self._get_session().get(self._url) as page:

                self._page = lxml.html.document_fromstring(await page.text())

        return self._page


犯罪嫌疑人X
浏览 132回答 2
2回答

一只甜甜圈

如何避免[多次请求]?你可以使用asyncio.Lock:saync def __init__(self, ...):    ...    self._page_lock = asyncio.Lock()async def _get_page(self) -> HtmlElement:    async with self._page_lock:        if self._page is None:            async with self._get_session().get(self._url) as page:                self._page = lxml.html.document_fromstring(await page.text())    return self._page

撒科打诨

Python 3.8 和 jupyter 笔记本的更新import asyncioimport aiohttpfrom lxml import htmlclass MyClass:    def __init__(self):        self._url = 'https://www.google.com'        self._page = None        self._futures = []        self._working = False        self._session = aiohttp.ClientSession()    async def _close(self):        if self._session:            session = self._session            self._session = None            await session.close()    def _get_session(self):        return self._session    async def _get_page(self):        if self._page is None:            if self._working:                print('will await current page request')                loop = asyncio.get_event_loop()                future = loop.create_future()                self._futures.append(future)                return await future            else:                self._working = True            session = self._get_session()            print('making url request')            async with session.get(self._url) as page:                print('status =', page.status)                print('making page request')                self._page = html.document_fromstring(await page.text())                print('Got page text')                for future in self._futures:                    print('setting result to awaiting request')                    future.set_result(self._page)                self._futures = []                self._working = False        return self._pageasync def main():    futures = []    m = MyClass()    futures.append(asyncio.ensure_future(m._get_page()))    futures.append(asyncio.ensure_future(m._get_page()))    futures.append(asyncio.ensure_future(m._get_page()))    results = await asyncio.gather(*futures)    for result in results:        print(result[0:80])    await m._close()if __name__ == '__main__':    asyncio.run(main())    #await main() # In jupyter notebook and iPython请注意,在 Windows 10 上,我在终止时看到:RuntimeError: Event loop is closed
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python