首页 > 解决方案 > Boto3:需要 Future 或协程

问题描述

我正在尝试使用 boto3 从 S3 下载 2 个文件,并等到 2 个文件下载完成后,将继续处理 2 个文件

我做了什么

async def download_files():
    await client.download_file(const.bucket_name, 'file/name.txt', '/tmp/name.txt')
    print('file 1 downloaded')
    await client.download_file(const.bucket_name, 'file/class.txt', '/tmp/class.txt')
    print('file 2 downloaded')
    return True

def main():
    ...
    loop = asyncio.get_event_loop()
    loop.run_until_complete(download_files())
    loop.close()
    ...
main()

我收到一个错误

A Future or coroutine is required

第一次用asyncio,求指教。

标签: python-3.xboto3python-asyncio

解决方案


boto3 不支持异步......它的功能是阻塞的,而不是等待的。因此,在这里要做的绝对最低限度就是await从对 的调用中删除download_file,它应该可以工作。

client.download_file(const.bucket_name, 'file/name.txt', '/tmp/name.txt')
print('file 1 downloaded')
client.download_file(const.bucket_name, 'file/class.txt', '/tmp/class.txt')
print('file 2 downloaded')
return True

但是,如果线程的事件循环中有任何其他并发任务,这将具有较差的并发属性:它们将被阻止并且在下载期间不会继续[这将使 asyncio 的使用有点不必要......并发正在进行的任务是异步的重点......]

为了获得更好的并发属性,您应该能够通过 调用函数run_in_executor,默认情况下它将在另一个线程中运行传递的函数。

async def download_files(loop):
  await loop.run_in_executor(None, client.download_file, const.bucket_name, 'file/name.txt', '/tmp/name.txt')
  print('file 1 downloaded')
  await loop.run_in_executor(None, client.download_file, const.bucket_name, 'file/class.txt', '/tmp/class.txt')
  print('file 2 downloaded')
  return True

或者,您可以使用aiohttp滚动您自己的 AWS 身份验证,而不是使用 boto3 和线程(完全披露:关于滚动您自己的 AWS 身份验证的帖子是我写的)


推荐阅读