PROBLEMA Come Posso usare Asyncio e Concurrent.futures insieme?

Leo_nard

Nuovo Utente
27
1
ciao a tutti, sto cercando di fare uno script python che manda delle richieste http il più velocemente possibile. In sostanza il programma prende una lista di url e fa delle richieste get in modo asyncrono con asyncio e aiohttp e poi salva le informazioni su file. Per ora il codice funziona bene, il problema è quando la lista di url supera i 200 o 300 elementi mettendoci un po di tempo... visto che asyncio usa un solo thread stavo pensando di usare il ThreadPool executor e splittare la lista di url in sottoliste e fa partire un thread asyncrono per ognuna di queste. Aggiungendo pero il ThreadPoolExecutor non funziona più il codice dandomi errori di coroutine e futures. Cercando su internet ho visto che dovrei usare "run_in_executor" o "run_thread_safe" ma non ho ben capito come usarle. Qualcuno potrebbe darmi una mano? Lascio il codice qua sotto.
Python:
async def fetch(url, session):
    async with session.get(url, ssl=False) as response:
        # if response.status == 200:
            html_body = await response.json()
            url = url.split('/')[-2]
            file_name = url if url != 'services' else 'live'
            async with aiofiles.open(f'{output_dir}/{file_name}.json', 'w') as f:
                await f.write(json.dumps(html_body, indent=4))
            return html_body
          
async def fetch_with_sem(sem, session, url):
    async with sem:
        return await fetch(url, session)

async def run(url, session, sem):
    tasks = [asyncio.create_task(fetch_with_sem(sem, session, url)) for url in url]
    page_content = await asyncio.gather(*tasks, return_exceptions=True)
    return page_content

async def main(urls):
    number = len(urls) // 10 + 1
    sem = asyncio.Semaphore(50)
    loop = asyncio.get_event_loop()
    print(loop)
    connector = aiohttp.TCPConnector(limit_per_host=30, limit=50, ttl_dns_cache=100)
    headers = {
        'user-agent': get_user_agent(),
        'sec-ch-ua-platform': "macOS",
        'sec-fetch-dest': 'empty',
        'sec-fetch-mode': 'cors',
        'sec-fetch-site': 'same-origin',
        'x-eb-accept-language': 'it_IT',
        'x-eb-marketid': '5',
        'x-eb-platformid': '1',
    }
    async with ClientSession(loop=loop, connector=connector, headers=headers) as session:
        if isinstance(urls, list):
            with ThreadPoolExecutor(max_workers=25) as executor:
                # page_content = [
                        # executor.submit(run, urls[number * i : number * (i + 1)], session, sem).result()
                #   for i in range(10) ]
                page_content = [
                        await loop.run_in_executor(executor, run, urls[number * i : number * (i + 1)], session, sem)
                    for i in range(10)]
        else:
            tasks = [asyncio.create_task(fetch_with_sem(sem, session, urls))]
            page_content = await asyncio.gather(*tasks, return_exceptions=True)
        return page_content
  




uvloop.install()
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
dic = scrape()
link = get_url(dic)
start = time.time()
x = asyncio.run(main(link))
end = time.time()
print("\nIt took {} seconds to make {} API calls\n".format(end-start, len(x)))

e ottengo questo errore:
Codice:
<uvloop.Loop running=True closed=False debug=False>
Traceback (most recent call last):
  File "/Users/federikowsky/Desktop/Python/Scraping/SureBet/prova.py", line 132, in <module>
    x = asyncio.run(main(link))
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "uvloop/loop.pyx", line 1501, in uvloop.loop.Loop.run_until_complete
  File "/Users/federikowsky/Desktop/Python/Scraping/SureBet/prova.py", line 115, in main
    page_content = [
  File "/Users/federikowsky/Desktop/Python/Scraping/SureBet/prova.py", line 116, in <listcomp>
    await loop.run_in_executor(executor, run, urls[number * i : number * (i + 1)], session, sem)
  File "uvloop/loop.pyx", line 2690, in uvloop.loop.Loop.run_in_executor
TypeError: coroutines cannot be used with run_in_executor()
 

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!