Проблема
Я использую FastAPI вместе с такими библиотеками, как Playwright, MongoDB и ThreadPoolExecutor. . Целью было использовать многопоточность для задач, связанных с ЦП, и асинхронное ожидание для задач, связанных с вводом-выводом. Тем не менее, время моего ответа не улучшилось, как ожидалось.
Пример автоматизации книг
Одна часть моего проекта включает автоматизацию запросов к книгам с использованием Playwright для взаимодействия с ними. программа просмотра EPUB. Следующая функция использует Playwright для открытия браузера, перехода на страницу книги и выполнения поиска:
Код: Выделить всё
from playwright.async_api import async_playwright
import asyncio
async def search_with_playwright(search_text: str, book_id: str):
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
book_id = book_id.replace("-1", "")
book_url = f"http://localhost:8002/book/{book_id}"
await page.goto(book_url)
await page.fill("#searchInput", search_text)
await page.click("#searchButton")
await page.wait_for_selector("#searchResults")
search_results = await page.evaluate('''
() => {
let results = [];
document.querySelectorAll("#searchResults ul li").forEach(item => {
let excerptElement = item.querySelector("strong:nth-of-type(1)");
let cfiElement = item.querySelector("strong:nth-of-type(2)");
if (excerptElement && cfiElement) {
let excerpt = excerptElement.nextSibling ? excerptElement.nextSibling.nodeValue.trim() : "";
let cfi = cfiElement.nextSibling ? cfiElement.nextSibling.nodeValue.trim() : "";
results.push({ excerpt, cfi });
}
});
return results;
}
''')
await browser.close()
return search_results
Примечание: я подсчитал, что время, необходимое для открытия книги и выполнения запроса к одной книге, составляет примерно 0,0028 с.
Я использовал run_in_executor() для выполнения функций в ProcessPoolExecutor, пытаясь избежать GIL и правильно управлять рабочими нагрузками.
Код: Выделить всё
async def query_mongo(query: str, id: str):
query_vector = generate_embedding(query)
results = db[id].aggregate([
{
"$vectorSearch": {
"queryVector": query_vector,
"path": "embedding",
"numCandidates": 2100,
"limit": 50,
"index": id
}
}
])
# Helper function for processing each document
def process_document(document):
try:
chunk = document["chunk"]
chapter = document["chapter"]
number = document["chapter_number"]
book_id = id
results = asyncio.run(search_with_playwright(chunk, book_id))
return {
"content": chunk,
"chapter": chapter,
"number": number,
"results": results,
}
except Exception as e:
print(f"Error processing document: {e}")
return None
# Using ThreadPoolExecutor for concurrency
all_data = []
with ThreadPoolExecutor() as executor:
futures = {executor.submit(process_document, doc): doc for doc in results}
for future in as_completed(futures):
try:
result = future.result()
if result: # Append result if it's not None
all_data.append(result)
except Exception as e:
print(f"Error in future processing: {e}")
return all_data
Даже после этих изменений мой API по-прежнему работает медленно. Что мне не хватает? Кто-нибудь сталкивался с подобными проблемами с настройками Python GIL, многопоточностью или асинхронностью? Будем очень признательны за любые советы!
Подробнее здесь: https://stackoverflow.com/questions/792 ... eading-21m
Мобильная версия