首頁 >後端開發 >Python教學 >為什麼我的多執行緒 API 仍然很慢?

為什麼我的多執行緒 API 仍然很慢?

DDD
DDD原創
2024-12-07 20:49:17793瀏覽

Why is My Multi-Threaded API Still Slow?

我的 API 遇到問題,希望有人可以幫忙。儘管添加了多線程,但效能提升遠沒有達到我的預期。理想情況下,如果一個執行緒需要 1 秒鐘來完成一項任務,那麼並發運行的 10 個執行緒也應該需要大約 1 秒鐘(這是我的理解)。然而,我的 API 回應時間仍然很慢。

問題

我正在使用 FastAPI 以及 Playwright、MongoDB 和 ThreadPoolExecutor 等函式庫。目標是對 CPU 密集型任務使用線程,對 IO 密集型任務使用非同步等待。儘管如此,我的回應時間並沒有像預期的那樣改善。

圖書自動化範例

我的專案的一部分涉及使用 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.0028s

重構範例

我使用 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、線程或非同步設定方面遇到類似的問題嗎?任何建議將不勝感激!

以上是為什麼我的多執行緒 API 仍然很慢?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn