gpt4 book ai didi

python - 脚本即使在异步运行时也执行得非常慢

转载 作者:太空宇宙 更新时间:2023-11-04 09:36:00 26 4
gpt4 key购买 nike

我在 asyncio 中编写了一个与 aiohttp 关联的脚本/em> 异步解析网站内容的库。我尝试按照通常在 scrapy 中应用的方式在以下脚本中应用逻辑。

但是,当我执行我的脚本时,它就像同步库一样 requests urllib.request 做。因此,它非常慢并且达不到目的。

我知道我可以通过在 link 变量中定义所有下一页链接来解决这个问题。但是,我不是已经以正确的方式使用现有脚本完成任务了吗?

在脚本中,processing_docs() 函数的作用是收集不同帖子的所有链接,并将优化后的链接传递给 fetch_again() 函数以获取标题从它的目标页面。 processing_docs() 函数中应用了一个逻辑,它收集 next_page 链接并将其提供给 fetch() 函数以重复相同的操作。 这个 next_page 调用使脚本变慢,而我们通常在 scrapy 中做同样的事情并获得预期的性能。

我的问题是:如何在保持现有逻辑不变的情况下实现相同的目标?

import aiohttp
import asyncio
from lxml.html import fromstring
from urllib.parse import urljoin

link = "https://stackoverflow.com/questions/tagged/web-scraping"

async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
text = await response.text()
result = await processing_docs(session, text)
return result

async def processing_docs(session, html):
tree = fromstring(html)
titles = [urljoin(link,title.attrib['href']) for title in tree.cssselect(".summary .question-hyperlink")]
for title in titles:
await fetch_again(session,title)

next_page = tree.cssselect("div.pager a[rel='next']")
if next_page:
page_link = urljoin(link,next_page[0].attrib['href'])
await fetch(page_link)

async def fetch_again(session,url):
async with session.get(url) as response:
text = await response.text()
tree = fromstring(text)
title = tree.cssselect("h1[itemprop='name'] a")[0].text
print(title)

if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(*(fetch(url) for url in [link])))
loop.close()

最佳答案

使用 asyncio 的全部意义在于您可以同时运行多个提取(彼此并行)。让我们看看您的代码:

for title in titles:
await fetch_again(session,title)

这部分意味着每个新的 fetch_again 只会在上一个等待(完成)之后开始。如果您这样做,是的,与使用同步方法没有区别。

要调用 asyncio 的所有功能,请使用 asyncio.gather 同时启动多个提取:

await asyncio.gather(*[
fetch_again(session,title)
for title
in titles
])

您会看到显着的加速。


您可以进一步进行事件并开始 fetch 获取下一页,同时 fetch_again 获取标题:

async def processing_docs(session, html):
coros = []

tree = fromstring(html)

# titles:
titles = [
urljoin(link,title.attrib['href'])
for title
in tree.cssselect(".summary .question-hyperlink")
]

for title in titles:
coros.append(
fetch_again(session,title)
)

# next_page:
next_page = tree.cssselect("div.pager a[rel='next']")
if next_page:
page_link = urljoin(link,next_page[0].attrib['href'])

coros.append(
fetch(page_link)
)

# await:
await asyncio.gather(*coros)

重要提示

虽然这种方法可以让您更快地做事,但您可能希望同时限制并发请求的数量,以避免在您的机器和服务器上使用大量资源。

为此,您可以使用 asyncio.Semaphore:

semaphore = asyncio.Semaphore(10)

async def fetch(url):
async with semaphore:
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
text = await response.text()
result = await processing_docs(session, text)
return result

关于python - 脚本即使在异步运行时也执行得非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53718961/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com