Почему выполнение асинхронной функции приводит к блокировке остальных операций в программе?

Как можно изменить код так, чтобы при вызове функции `mainGoogleDoc()` остальные запросы не блокировались, а продолжали обрабатываться?
  • 26 февраля 2024 г. 10:08
Ответы на вопрос 4
Асинхронная функция может привести к блокировке остальных операций в программе, если она выполняет длительные операции синхронно, то есть не допускает переключения контекста выполнения на другие части программы. Это может произойти, например, если функция выполняет запрос к внешнему ресурсу, который отвечает медленно.

Чтобы избежать блокировки остальных операций в программе, можно использовать асинхронные операции, например, с помощью модуля `asyncio` в Python. Вместо выполнения запроса к внешнему ресурсу синхронно, можно использовать асинхронные функции и `await`, чтобы дать возможность другим частям программы продолжать работу во время выполнения длительной операции.

Пример изменения кода с использованием `asyncio`:

```python
import asyncio

async def mainGoogleDoc():
    print("Starting mainGoogleDoc")
    await asyncio.sleep(5) # Симуляция длительной операции
    print("Finished mainGoogleDoc")

async def otherOperation():
    print("Starting otherOperation")
    await asyncio.sleep(2)
    print("Finished otherOperation")

async def main():
    task1 = asyncio.create_task(mainGoogleDoc())
    task2 = asyncio.create_task(otherOperation())
    
    await task1
    await task2

asyncio.run(main())
```

В данном примере функция `main()` создает два асинхронных задания `task1` и `task2`, которые выполняются параллельно. Таким образом, при вызове функции `mainGoogleDoc()` остальные операции не блокируются и продолжают работу.
Всем спасибо за помощь, вот связка которая решила мою проблему: 
Если нет желания искать или подобная асинхронная версия библиотеки отсутствует, можно использовать следующую запись:
# Функция для запуска синхронного кода в run_in_executor
async def run_sync_in_executor(sync_func):
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(None, sync_func)

# Измененная основная функция для запуска синхронного кода в run_in_executor
async def mainGoogleDoc():
    try:
        text1 = await run_sync_in_executor(userListInGoogle)
        text2 = await run_sync_in_executor(secondStageInList)
        text3 = await run_sync_in_executor(thirdStageInList)
        text4 = await run_sync_in_executor(referalsInList)
        print(text1,text2,text3,text4)
        if text1 == "DONE" and text2 == "DONE" and text3 == "DONE" and text4 == "DONE":
            text = "DONE"
            return text
    except Exception as e:
        text = "Google Docs Error"
        print(f"Google Docs Error {e}")
        return text


Перед этим я убрал для каждой из функции подпись async def.... сделав её синхронной
Хотя Вы и используете асинхронный код выше (в telegram боте), Ваши функции, которые работают с google sheets и бд, работают синхронно. В этом случае, даже если Вы оборачиваете их в await, то они чудесным образом не станут асинхронными и все равно заблокируют исполнение асинхронного eventloop, пока не завершат свою работу. 

Чтобы решить Вашу проблему, необходимо использовать библиотеки, которые умеют в асинхронную работу, бд - aiosqlite , а с google sheets - хз, вроде подходит gspread_asyncio .
учитывая то, что все функции асинхронные?
а с чего ты решил что они все асинхронные? С базой ты синхронно работаешь, а у gspread поди синхронные http запросы (это и будет основное место блокирови). Ищи асинк версии этих библиотек или запускай синхронный код в run_in_executor
Похожие вопросы