为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

犯罪嫌疑人X 2023-08-15 18:54:17
在我的课堂上,我有一个获取网站的方法(如下所示)。我注意到使用此方法的其他方法可能会导致向一个站点打开多个请求(当一个请求待处理时 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
查看完整描述

2 回答

?
一只甜甜圈

TA贡献1836条经验 获得超5个赞

如何避免[多次请求]?

你可以使用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


查看完整回答
反对 回复 2023-08-15
?
撒科打诨

TA贡献1934条经验 获得超2个赞

Python 3.8 和 jupyter 笔记本的更新


import asyncio

import aiohttp

from lxml import html



class 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._page



async 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


查看完整回答
反对 回复 2023-08-15
  • 2 回答
  • 0 关注
  • 131 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信