首页 > 解决方案 > 在 Python 中使用带有 for 循环的 Asyncio,类似于 Javascript 中的 map 方法和 promise.all

问题描述

我正在尝试在 Python 中异步运行 for 循环,就像您可以在 Javascript 中使用 map 方法和 promise.all 一样。我到处搜索如何做到这一点,但下面的代码仍然是同步运行的(一个接一个地运行,而不是让循环在完成之前的迭代时进行其他迭代,比如 promise.all 允许你)。任何帮助,将不胜感激。

from jwt import scopes                                                   
from googleapiclient.discovery import build
from google.oauth2 import service_account
import json
import asyncio

key = 'file.json'
ID = 'ID'
rg = 'A1'

j2 = service_account.Credentials.from_service_account_file(key, scopes=scopes).with_subject('me@emial.com')

ar = []
cl = build('classroom', 'v1', credentials=j2)

def cour():
    co = []
    result1 = cl.courses().list().execute()
    courses = result1.get('courses', [])
    for cc in courses:
        co.append(cc['id'])
    return co

cco = cour()

async def main():
    async def subs2(i):
        await asyncio.sleep(0)
        result2 = cl.courses().courseWork().list(courseId=i).execute() 
        works = result2.get('courseWork', [])

        for work in works:
            result = cl.courses().courseWork().studentSubmissions().list(courseId=work['courseId'], courseWorkId=work['id']).execute()
            subs = result.get('studentSubmissions', [])

            for sub in subs:
                try:
                    ar.append(sub['assignedGrade'])
                    ar.append(sub['courseId'])
                    ar.append(sub['courseWorkId'])
                    ar.append(sub['userId'])
                except KeyError as name: 
                    pass

    coros = [subs2(i) for i in cco]
    await asyncio.gather(*coros)

if __name__ == '__main__':
    cour()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.close()

标签: javascriptpythonpython-3.xpython-asynciogoogle-apps

解决方案


我认为您误解了asyncio提供并发性的方式。它不会产生任何额外的线程或进程。事件循环以及在其上运行的所有协程都在单个线程中执行。为了获得并发性,您的协程需要await调用执行异步 I/O 或其他一些可以控制异步事件循环的操作。

在您的示例中,您尝试同时运行的协程实际上并没有执行任何异步 I/O。所以每次协程执行时,它都会阻塞事件循环,直到它完成。这意味着每个都将按顺序执行。为了获得并发性,您需要使用对异步友好的库而不是googleapiclient您当前正在使用的库 ( ),或者使用loop.run_in_executor.


推荐阅读