gpt4 book ai didi

python - 在 Python 中使用 asyncio 并行化 Web 任务

转载 作者:太空宇宙 更新时间:2023-11-04 01:12:51 25 4
gpt4 key购买 nike

我正试图全神贯注于 asyncio 和 aiohttp,多年来编程让我第一次感到自己非常愚蠢和无能。这有点漂亮,以一种古怪的禅宗方式。但是,唉,还有工作要做。

我有一个现有的类可以在网络上做许多奇妙的事情,比如注册网站、获取数据等。现在我需要 100 或 1000 只这样的小工蜂来注册。代码大致如下所示:

class Worker(object):
def signup(self, ...):
...
data = self.make_request(url, data)
self.user_id = data.get("user_id")
return self

def make_request(self, url, data):
response = requests.post(url, data=data)
return response.json()

workers = [Worker().signup() for n in range(100)]

如您所见,我们正在使用请求模块发出 POST 请求。然而,这是阻塞的,所以我们必须等待 worker N 完成注册,然后才能开始注册 worker N+1。幸运的是,Worker 类的原作者(这听起来很有马克思主义色彩)以她无限的智慧将每个 HTTP 调用都包装在 self.make_request 方法中,所以让整个 Worker 非阻塞应该只是一个问题将请求库换成一个非阻塞的 aaaa 和 bob 是你的叔叔,对吧?这是我得到的结果:

class AyncWorker(Worker):
@asyncio.coroutine
def make_request(self, url, data):
response = yield from aiohttp.request('post', url, data=data)
return (yield from response.json())

coroutines = [Worker().signup() for n in range(100)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(coroutines))
loop.close()

但是这会在 signup 方法中引发一个 AttributeError: 'generator' object has no attribute 'get' 我做 self.user_id = data.获取(“用户 ID”)。除此之外,我仍然没有一本整洁的字典中的 worker 。我知道我很可能完全误解了 asyncio 的工作原理——但我已经花了一天时间阅读各种文档、David Beazly 令人心碎的教程,以及大量足以让我理解它们的玩具示例简单适用于这种情况。我应该如何构建我的工作人员和我的异步循环以并行注册 100 个工作人员并最终在他们注册后获得所有工作人员的列表?

最佳答案

一旦你在一个函数中使用了yield(或yield from),这个函数就变成了协程。这意味着您无法仅通过调用它来获得结果:您将获得一个generator object。您至少必须这样做:

@asyncio.coroutine
def some_coroutine(*args):
#...
#...
yield from tasty.asyncio.function()
return result

def coroutine_user():
# data = some_coroutine() will give you a generator object instead of result
data = yield from some_coroutine()
return data # data here is a plain result: you can call your .get or whatever

猜猜调用 coroutine_user() 时会发生什么:

>>> coroutine_user()
<generator object coroutine_user at 0x7fe13b8a47e0>

缺少 async.coroutine 装饰器根本无济于事:协程具有传染性!要在函数中获取结果,您必须使用 yield from。它将您的函数变成另一个协程!

虽然事情并不总是那么糟糕(通常你可以手动迭代生成器对象而不依赖于 yield from),asyncio 会特别阻止你这样做:它破坏了一些内部结构(你可以仅从 Future 或 asyncio.coroutine 执行)。所以只要使用 concurrent.futures 或类似的东西,除非你要把你所有的代码都变成协程。作为替代方案,将 aiohttp.request 的所有用户与常用方法隔离开来,并使用基于协程的异步 worker 和同步纯旧代码。深入研究 asyncio 并实际重构所有代码也是一种选择,显然:您基本上需要在每次调用任何受感染的 asyncio 方法之前放置 yield from

关于python - 在 Python 中使用 asyncio 并行化 Web 任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26606660/

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