[{"data":1,"prerenderedAt":2479},["ShallowReactive",2],{"blog-20260304-troublemaker":3,"related-20260304-troublemaker":366},{"id":4,"title":5,"author":6,"body":7,"category":346,"date":347,"description":348,"draft":349,"extension":350,"image":351,"meta":352,"navigation":353,"path":354,"seo":355,"stem":356,"tags":357,"__hash__":365},"blog/blog/20260304-troublemaker.md","關於我一天在公司 AWS 開發帳號花掉 14000 鎂的那回事","Ting Zhang",{"type":8,"value":9,"toc":325},"minimark",[10,19,22,27,34,37,48,57,64,67,83,86,91,94,97,105,108,111,114,119,122,126,129,134,143,156,159,167,172,175,178,183,186,194,199,203,206,217,221,224,231,238,241,244,247,250,253,256,259,262,266,269,272,278,282,285,296,300,303,310,313,316,319,322],[11,12,13,14,18],"p",{},"身為工程師，你可能聽過同事不小心把 Production 資料庫砍了、或是忘記關 EC2 多燒了幾百塊。但你有聽過",[15,16,17],"strong",{},"用雲服務一天燒掉 14,000 美金","的嗎？",[11,20,21],{},"沒錯，這件事發生在我身上...嗎？",[23,24,26],"h2",{"id":25},"tldr","TL;DR",[11,28,29,30,33],{},"在公司開發帳號 survey AWS Bedrock AgentCore Policy 功能，試用了 Cedar Policy Generator。幾天後帳單突然出現一筆 ",[15,31,32],{},"$14,000+ USD 的單日費用","。經過 CloudTrail 排查確認是 Cedar Generator 觸發的異常計費，最終 AWS 承認是 Bedrock 端的計費 bug，修復並校正了帳單。",[23,35,36],{"id":36},"事發經過",[11,38,39,40,47],{},"3/4 我因為看到 ",[41,42,46],"a",{"href":43,"rel":44},"https://aws.amazon.com/bedrock/agentcore/",[45],"nofollow","AgentCore"," 新 Feature - Policy 剛上線，所以需要 Survey 一下。",[11,49,50,51,56],{},"AgentCore Policy 讓你可以用 ",[41,52,55],{"href":53,"rel":54},"https://www.cedarpolicy.com/",[45],"Cedar"," 語言來定義 Agent 的授權策略，控制 Agent 能存取哪些工具和資源。Cedar 是 AWS 開源的授權語言，語法可讀性很高，設計上是要讓非工程師也能看得懂的那種。",[11,58,59,60,63],{},"而 AgentCore 很貼心地提供了一個 ",[15,61,62],{},"Natural Language Policy Generator","——你用自然語言描述你要的權限規則，它就幫你生成對應的 Cedar Policy。聽起來很 User-friendly 對吧？",[11,65,66],{},"我就照著文件走了一遍流程：",[68,69,70,74,77,80],"ol",{},[71,72,73],"li",{},"建了一個 Policy Engine",[71,75,76],{},"試了幾次 Cedar Policy Generator（用自然語言描述轉成 Cedar）",[71,78,79],{},"確認功能可以正常運作",[71,81,82],{},"收工，覺得這功能還不錯",[11,84,85],{},"整個過程大概就一兩個小時，正常的 survey 流程。",[11,87,88],{},[15,89,90],{},"然後就沒有然後了——直到五天後。",[23,92,93],{"id":93},"帳單爆炸",[11,95,96],{},"後來請假看完中華隊在 WBC 的比賽，打贏韓國那場實在很感動，回來上班的第一天，3/9 下午，Slack突然被狂 tag，我被我們公司的 Billing Manager & Team Lead 問為何會有一筆費用產生，我也趕緊地打開CE，一個讓我愣住的數字：",[98,99,100],"blockquote",{},[11,101,102],{},[15,103,104],{},"3/4 單日Agentcore產生了 $14,000+ USD的費用",[11,106,107],{},"我先是以為自己眼花了。重新整理頁面，數字還在那裡。",[11,109,110],{},"完了... 哪裡搞錯了吧？",[23,112,113],{"id":113},"排查過程",[115,116,118],"h3",{"id":117},"step-1先開-support-ticket","Step 1：先開 Support Ticket",[11,120,121],{},"不管三七二十一，先開 AWS Support Ticket 回報異常帳單。把時間範圍、帳號資訊、異常金額都附上去，讓 Support 那邊開始調查。",[115,123,125],{"id":124},"step-2自己也同步排查","Step 2：自己也同步排查",[11,127,128],{},"等 Support 回覆的同時，我也開始自己排查紀錄。",[11,130,131],{},[15,132,133],{},"確認 AgentCore Policy 的收費機制",[11,135,136,137,142],{},"根據 ",[41,138,141],{"href":139,"rel":140},"https://aws.amazon.com/bedrock/agentcore/pricing/",[45],"AgentCore 定價頁面","，Policy 的計費主要是：",[144,145,146,153],"ul",{},[71,147,148,149,152],{},"Cedar Policy Generator：",[15,150,151],{},"按 input token 數量計費","（每 1,000 tokens）",[71,154,155],{},"Policy Engine 的 Authorization 請求：按請求數計費",[11,157,158],{},"稍微思考一下：",[68,160,161,164],{},[71,162,163],{},"我當天的使用量根本不可能撐到這個金額。就算我瘋狂打 Generator 也打不出 $14,000，同事跟我說 Billing 那邊顯示 Policy 使用了 109 1M Tokens (接近 1.1 億，我甚至不知道一天要怎麼用掉那麼多 Tokens...)。",[71,165,166],{},"我的 Policy Engine 並沒有 Attach Gateway，所以也沒有真正的使用 Policy 這個 Feature。",[11,168,169],{},[15,170,171],{},"確認 Runtime 沒有產生額外費用",[11,173,174],{},"AgentCore Runtime 是按 CPU 和記憶體的秒級消耗來計費的。我需要確保沒有遺留的 Runtime 在背景持續運作，或者跟 Gateway 掛鉤產生連鎖費用。",[11,176,177],{},"檢查結果：沒有任何遺留資源在跑。",[11,179,180],{},[15,181,182],{},"CloudTrail",[11,184,185],{},"我拉出了那段時間的 CloudTrail 紀錄，逐筆檢查跟 AgentCore 相關的 API 呼叫。",[11,187,188,189,193],{},"最終鎖定是 ",[190,191,192],"code",{},"StartPolicyGeneration"," 這個 API 呼叫。從紀錄上看，我確實只有呼叫了3次，請求量完全不合理對應到那個帳單金額。",[11,195,196],{},[15,197,198],{},"結論：應該不是我的使用量有問題，是計費那邊有問題。",[115,200,202],{"id":201},"step-3跟-support-同步","Step 3：跟 Support 同步",[11,204,205],{},"我把 CloudTrail 的排查結果整理好，回覆到 Support Ticket 上。附上了：",[144,207,208,211,214],{},[71,209,210],{},"明確的 API 呼叫時間和次數",[71,212,213],{},"計費金額的不合理性說明",[71,215,216],{},"我這邊已經確認沒有遺留資源",[115,218,220],{"id":219},"step-4aws-確認是計費-bug","Step 4：AWS 確認是計費 Bug",[11,222,223],{},"AWS Support 將 case 轉給了 Bedrock 團隊。Bedrock 團隊調查後確認：",[98,225,226],{},[11,227,228],{},[15,229,230],{},"Cedar Policy Generator 存在計費問題，導致實際計費金額遠超正常使用量應有的費用。",[11,232,233,234,237],{},"他們修復了這個計費 bug，並且",[15,235,236],{},"校正了帳單","。",[11,239,240],{},"結案。",[23,242,243],{"id":243},"心理狀態",[11,245,246],{},"看到 $14,000 這個數字的時候，腦袋裡跑過各種最壞的劇本——會不會要自己賠？這是我好幾個月的薪水總和，光想就覺得可怕。",[11,248,249],{},"即使理性上告訴自己先查原因再說，甚至基本上確定不是我這邊的問題，但焦慮感還是壓不住。",[11,251,252],{},"這幾天嚴重睡眠不足，每天躺在床上腦袋還在轉「到底是哪裡出問題」。腸胃也跟著出狀況，一直拉肚子。壓力對身體的影響比我想像中來得直接。",[11,254,255],{},"最後當 CloudTrail 的證據越來越明確指向計費問題，Support 也確認 Bedrock 團隊發現問題並正在進行修復，我的心情才開始慢慢平復。",[23,257,258],{"id":258},"事後反思",[11,260,261],{},"雖然這次最後證實是 AWS 的計費 bug，但整個事件讓我學到了很多。",[115,263,265],{"id":264},"_1-工作紀錄真的很重要","1. 工作紀錄真的很重要",[11,267,268],{},"當下會感到慌張的原因，很大一部分來自 Context 不足，一來我不確定 Agentcore Policy 是如何計費，為何可以用到那麼貴？二來我不知道我5天前具體做了什麼操作。",[11,270,271],{},"如果我當初 survey 的時候沒有留下操作紀錄，排查的時候會更加困難。CloudTrail 能幫你查到 API 呼叫，但你自己當時在做什麼、為什麼做，這些 context 只有你自己知道。",[11,273,274,277],{},[15,275,276],{},"養成習慣：每次操作不熟的雲服務時，簡單記錄一下你做了什麼。"," 不需要多詳細，一個簡單的筆記或是 Slack 訊息就夠了。關鍵時刻這些紀錄可以救你一命。",[115,279,281],{"id":280},"_2-使用前搞懂計費方式","2. 使用前搞懂計費方式",[11,283,284],{},"這聽起來像廢話，但真的很多人（包括我）在 survey 新服務的時候會直接跳進去玩，不會先仔細看定價頁面。",[144,286,287,290,293],{},[71,288,289],{},"開始 survey 前，先看過定價頁面",[71,291,292],{},"特別注意按量計費的服務，搞清楚「量」是怎麼定義的",[71,294,295],{},"開發帳號最好設定 Budget Alert，超過閾值自動通知",[115,297,299],{"id":298},"_3-先了解公司的處理流程","3. 先了解公司的處理流程",[11,301,302],{},"事發的時候，我其實不太確定公司對這種事情的態度和處理方式。後來跟主管報告時，主管第一句話就是：",[98,304,305],{},[11,306,307],{},[15,308,309],{},"「不可能叫你賠的，先搞清楚狀況就好。」",[11,311,312],{},"這句話讓我放下了很大的心理負擔。每間公司的文化不同，但我想大部分公司都不會因為合理操作導致的意外費用而讓員工賠償。",[23,314,315],{"id":315},"結語",[11,317,318],{},"回頭看這件事，蠻慶幸最後不是我的問題，也慶幸公司的主管很 Nice",[11,320,321],{},"這次經歷讓我建立起了面對雲端成本異常的 SOP。以前覺得帳單管理是 FinOps 團隊的事，現在覺得每個會碰到雲服務的工程師都應該有基本的成本意識。",[11,323,324],{},"題外話，這讓我想到我大學時期第一次買股票的時候，我買了3股台積電花了大概 2000塊吧，當時每天看著損益正負三四百塊就能很影響我的心情，影響我做事與學習的效率，直到今天可能每天的損益就是一個月的薪水，我還是照常做著自己的事情。我想有了這次經驗，肯定能讓我在未來遇到類似的事情的時候心態更穩健吧。",{"title":326,"searchDepth":327,"depth":327,"links":328},"",2,[329,330,331,332,339,340,345],{"id":25,"depth":327,"text":26},{"id":36,"depth":327,"text":36},{"id":93,"depth":327,"text":93},{"id":113,"depth":327,"text":113,"children":333},[334,336,337,338],{"id":117,"depth":335,"text":118},3,{"id":124,"depth":335,"text":125},{"id":201,"depth":335,"text":202},{"id":219,"depth":335,"text":220},{"id":243,"depth":327,"text":243},{"id":258,"depth":327,"text":258,"children":341},[342,343,344],{"id":264,"depth":335,"text":265},{"id":280,"depth":335,"text":281},{"id":298,"depth":335,"text":299},{"id":315,"depth":327,"text":315},"技術","2026-03-18","Survey AWS AgentCore Policy完，過了幾天以後才發現帳單噴了14000...",false,"md","/images/blog/20260304-troublemaker/banner.png",{},true,"/blog/20260304-troublemaker",{"title":5,"description":348},"blog/20260304-troublemaker",[358,359,360,361,362,363,364],"AWS","雲端","成本控管","經驗分享","踩雷","DevOps","雲服務","6QyxVCpq8RjfovhyvoS0butlFVU7bQKJ1pfTGyL4M1Q",[367,1846,2085],{"id":368,"title":369,"author":6,"body":370,"category":346,"date":1835,"description":1836,"draft":349,"extension":350,"image":326,"meta":1837,"navigation":353,"path":1838,"seo":1839,"stem":1840,"tags":1841,"__hash__":1845},"blog/blog/concurrency.md","Python 並發處理方法",{"type":8,"value":371,"toc":1814},[372,376,379,382,385,389,436,440,475,479,512,516,534,537,685,688,1385,1388,1640,1644,1650,1668,1672,1677,1695,1698,1703,1707,1710,1714,1717,1731,1735,1738,1784,1787,1810],[23,373,375],{"id":374},"這篇文章的用處","這篇文章的用處？",[11,377,378],{},"若專案內有遇到效能瓶頸，這可能可以幫助你加速。",[11,380,381],{},"Python 提供了幾種並發方式，每種方式適用於不同類型的任務。",[23,383,384],{"id":384},"各方式介紹",[115,386,388],{"id":387},"_1-多線程multithreading","1. 多線程（Multithreading）",[144,390,391,397,418,424,430],{},[71,392,393,396],{},[15,394,395],{},"特點","：由於 GIL 的存在，多線程無法實現真正的並行，線程間由解釋器切換執行。",[71,398,399,402,403,406,407],{},[15,400,401],{},"適用場景","：適合 ",[15,404,405],{},"I/O 綁定任務","，如：\n",[144,408,409,412,415],{},[71,410,411],{},"API 呼叫",[71,413,414],{},"檔案讀寫",[71,416,417],{},"使用者輸入等待",[71,419,420,423],{},[15,421,422],{},"限制","：在 CPU 綁定任務（如計算 Fibonacci 數列）中，效能與單線程迴圈相差無幾。",[71,425,426,429],{},[15,427,428],{},"優點","：線程間資料共享簡單，記憶體開銷低。",[71,431,432,435],{},[15,433,434],{},"缺點","：受 GIL 限制，無法利用多核心。",[115,437,439],{"id":438},"_2-多進程multiprocessing","2. 多進程（Multiprocessing）",[144,441,442,447,465,470],{},[71,443,444,446],{},[15,445,395],{},"：每個進程擁有獨立的 Python 解釋器和 GIL，因此可以在不同 CPU 核心上實現真正的並行。",[71,448,449,402,451,406,454],{},[15,450,401],{},[15,452,453],{},"CPU 綁定任務",[144,455,456,459,462],{},[71,457,458],{},"數學運算",[71,460,461],{},"圖像處理",[71,463,464],{},"日誌分析",[71,466,467,469],{},[15,468,428],{},"：繞過 GIL，實現真並行，速度較快。",[71,471,472,474],{},[15,473,434],{},"：記憶體使用量高，進程間資料共享較複雜（需使用管道或共享記憶體）。",[115,476,478],{"id":477},"_3-asyncio","3. Asyncio",[144,480,481,486,502,507],{},[71,482,483,485],{},[15,484,395],{},"：使用協程（coroutines）實現非阻塞的並發，適合 I/O 綁定任務。",[71,487,488,490,491],{},[15,489,401],{},"：\n",[144,492,493,496,499],{},[71,494,495],{},"網路請求",[71,497,498],{},"檔案 I/O",[71,500,501],{},"其他等待外部資源的任務",[71,503,504,506],{},[15,505,428],{},"：輕量，記憶體使用效率高。",[71,508,509,511],{},[15,510,434],{},"：不適合 CPU 密集型任務，因為它並非真正的並行。",[115,513,515],{"id":514},"_4-第三方庫","4. 第三方庫",[144,517,518,524,529],{},[71,519,520,523],{},[15,521,522],{},"例子","：Cython、NumPy、Pandas、PyTorch 等。",[71,525,526,528],{},[15,527,395],{},"：這些庫通常使用 C 語言實現，部分操作可繞過 GIL，提供高效能。",[71,530,531,533],{},[15,532,401],{},"：特定計算密集型任務（如矩陣運算）。",[23,535,536],{"id":536},"特性比較表",[538,539,540,562],"table",{},[541,542,543],"thead",{},[544,545,546,550,553,556,559],"tr",{},[547,548,549],"th",{},"特性",[547,551,552],{},"Multi-threading",[547,554,555],{},"Multi-processing",[547,557,558],{},"AsyncIO",[547,560,561],{},"Disabled GIL",[563,564,565,583,600,618,635,651,666],"tbody",{},[544,566,567,573,576,579,581],{},[568,569,570],"td",{},[15,571,572],{},"並行",[568,574,575],{},"❌",[568,577,578],{},"✅",[568,580,575],{},[568,582,578],{},[544,584,585,590,593,596,598],{},[568,586,587],{},[15,588,589],{},"記憶體共享",[568,591,592],{},"容易",[568,594,595],{},"困難",[568,597,592],{},[568,599,592],{},[544,601,602,607,610,613,615],{},[568,603,604],{},[15,605,606],{},"記憶體使用",[568,608,609],{},"低",[568,611,612],{},"高",[568,614,609],{},[568,616,617],{},"中等",[544,619,620,625,628,631,633],{},[568,621,622],{},[15,623,624],{},"CPU 密集型",[568,626,627],{},"差",[568,629,630],{},"好",[568,632,627],{},[568,634,630],{},[544,636,637,642,644,646,649],{},[568,638,639],{},[15,640,641],{},"I/O 密集型",[568,643,630],{},[568,645,617],{},[568,647,648],{},"最佳",[568,650,630],{},[544,652,653,658,660,662,664],{},[568,654,655],{},[15,656,657],{},"實作複雜度",[568,659,617],{},[568,661,612],{},[568,663,617],{},[568,665,612],{},[544,667,668,673,676,679,682],{},[568,669,670],{},[15,671,672],{},"競爭條件風險",[568,674,675],{},"低（GIL保護）",[568,677,678],{},"低（隔離）",[568,680,681],{},"無（單執行緒）",[568,683,684],{},"高（需手動處理）",[23,686,687],{"id":687},"範例程式碼",[689,690,694],"pre",{"className":691,"code":692,"language":693,"meta":326,"style":326},"language-python shiki shiki-themes github-light github-dark","import time\nimport threading\nimport multiprocessing\nimport asyncio\nimport sys\nfrom concurrent.futures import ThreadPoolExecutor\nfrom functools import wraps\n\n# 計時裝飾器，用於測量執行時間\ndef timing_decorator(func):\n    @wraps(func)\n    def wrapper(*args, **kwargs):\n        start = time.time()\n        result = func(*args, **kwargs)\n        end = time.time()\n        print(f\"{func.__name__} 執行時間: {end - start:.4f} 秒\")\n        return result\n    return wrapper\n\n# CPU 密集型任務：計算 Fibonacci 數列\ndef fib(n):\n    if n \u003C= 1:\n        return n\n    return fib(n - 1) + fib(n - 2)\n\n# I/O 綁定任務：模擬網路請求（全局函數）\ndef sync_io_task():\n    time.sleep(1)  # 模擬 1 秒的 I/O 延遲\n\n# 異步 I/O 任務\nasync def io_bound_task():\n    await asyncio.sleep(1)  # 模擬 1 秒的 I/O 延遲\n    return \"I/O 任務完成\"\n\n# 多線程實現\n@timing_decorator\ndef run_multithreading(n_tasks, task_type=\"cpu\"):\n    threads = []\n    if task_type == \"cpu\":\n        for _ in range(n_tasks):\n            t = threading.Thread(target=fib, args=(35,))\n            threads.append(t)\n            t.start()\n        for t in threads:\n            t.join()\n    else:  # I/O 任務\n        for _ in range(n_tasks):\n            t = threading.Thread(target=sync_io_task)\n            threads.append(t)\n            t.start()\n        for t in threads:\n            t.join()\n\n# 多進程實現\n@timing_decorator\ndef run_multiprocessing(n_tasks, task_type=\"cpu\"):\n    processes = []\n    if task_type == \"cpu\":\n        for _ in range(n_tasks):\n            p = multiprocessing.Process(target=fib, args=(35,))\n            processes.append(p)\n            p.start()\n        for p in processes:\n            p.join()\n    else:  # I/O 任務\n        for _ in range(n_tasks):\n            p = multiprocessing.Process(target=sync_io_task)\n            processes.append(p)\n            p.start()\n        for p in processes:\n            p.join()\n\n# Asyncio 實現\n@timing_decorator\nasync def run_asyncio(n_tasks):\n    tasks = [io_bound_task() for _ in range(n_tasks)]\n    await asyncio.gather(*tasks)\n\n# 禁用 GIL 的多線程實現（需 Python 3.13 --disable-gil）\n@timing_decorator\ndef run_nogil_multithreading(n_tasks, task_type=\"cpu\"):\n    with ThreadPoolExecutor(max_workers=n_tasks) as executor:\n        if task_type == \"cpu\":\n            futures = [executor.submit(fib, 35) for _ in range(n_tasks)]\n        else:  # I/O 任務\n            futures = [executor.submit(sync_io_task) for _ in range(n_tasks)]\n        for future in futures:\n            future.result()\n\n# 主程式\nif __name__ == \"__main__\":\n    n_tasks = 4  # 任務數量\n\n    print(\"=== CPU 密集型任務 (計算 Fibonacci 數列) ===\")\n    print(\"多線程 (Multithreading):\")\n    run_multithreading(n_tasks, task_type=\"cpu\")\n\n    print(\"\\n多進程 (Multiprocessing):\")\n    run_multiprocessing(n_tasks, task_type=\"cpu\")\n\n    if sys.version_info >= (3, 13) and hasattr(sys, \"disable_gil\"):\n        print(\"\\n禁用 GIL 的多線程:\")\n        run_nogil_multithreading(n_tasks, task_type=\"cpu\")\n    else:\n        print(\"\\n禁用 GIL 的多線程: 需要 Python 3.13 並啟用 --disable-gil\")\n\n    print(\"\\n=== I/O 綁定任務 (模擬網路請求) ===\")\n    print(\"多線程 (Multithreading):\")\n    run_multithreading(n_tasks, task_type=\"io\")\n\n    print(\"\\n多進程 (Multiprocessing):\")\n    run_multiprocessing(n_tasks, task_type=\"io\")\n\n    print(\"\\nAsyncio:\")\n    asyncio.run(run_asyncio(n_tasks))\n\n    if sys.version_info >= (3, 13) and hasattr(sys, \"disable_gil\"):\n        print(\"\\n禁用 GIL 的多線程:\")\n        run_nogil_multithreading(n_tasks, task_type=\"io\")\n    else:\n        print(\"\\n禁用 GIL 的多線程: 需要 Python 3.13 並啟用 --disable-gil\")\n","python",[190,695,696,704,709,714,720,726,732,738,744,750,756,762,768,774,780,786,792,798,804,809,815,821,827,833,839,844,850,856,862,867,873,879,885,891,896,902,908,914,920,926,932,938,944,950,956,962,968,973,979,984,989,994,999,1004,1010,1015,1021,1027,1032,1037,1043,1049,1055,1061,1067,1072,1077,1083,1088,1093,1098,1103,1108,1114,1119,1125,1131,1137,1142,1148,1153,1159,1165,1171,1177,1183,1189,1195,1201,1206,1212,1218,1224,1229,1235,1241,1247,1252,1258,1264,1269,1275,1281,1287,1293,1299,1304,1310,1315,1321,1326,1331,1337,1342,1348,1354,1359,1364,1369,1375,1380],{"__ignoreMap":326},[697,698,701],"span",{"class":699,"line":700},"line",1,[697,702,703],{},"import time\n",[697,705,706],{"class":699,"line":327},[697,707,708],{},"import threading\n",[697,710,711],{"class":699,"line":335},[697,712,713],{},"import multiprocessing\n",[697,715,717],{"class":699,"line":716},4,[697,718,719],{},"import asyncio\n",[697,721,723],{"class":699,"line":722},5,[697,724,725],{},"import sys\n",[697,727,729],{"class":699,"line":728},6,[697,730,731],{},"from concurrent.futures import ThreadPoolExecutor\n",[697,733,735],{"class":699,"line":734},7,[697,736,737],{},"from functools import wraps\n",[697,739,741],{"class":699,"line":740},8,[697,742,743],{"emptyLinePlaceholder":353},"\n",[697,745,747],{"class":699,"line":746},9,[697,748,749],{},"# 計時裝飾器，用於測量執行時間\n",[697,751,753],{"class":699,"line":752},10,[697,754,755],{},"def timing_decorator(func):\n",[697,757,759],{"class":699,"line":758},11,[697,760,761],{},"    @wraps(func)\n",[697,763,765],{"class":699,"line":764},12,[697,766,767],{},"    def wrapper(*args, **kwargs):\n",[697,769,771],{"class":699,"line":770},13,[697,772,773],{},"        start = time.time()\n",[697,775,777],{"class":699,"line":776},14,[697,778,779],{},"        result = func(*args, **kwargs)\n",[697,781,783],{"class":699,"line":782},15,[697,784,785],{},"        end = time.time()\n",[697,787,789],{"class":699,"line":788},16,[697,790,791],{},"        print(f\"{func.__name__} 執行時間: {end - start:.4f} 秒\")\n",[697,793,795],{"class":699,"line":794},17,[697,796,797],{},"        return result\n",[697,799,801],{"class":699,"line":800},18,[697,802,803],{},"    return wrapper\n",[697,805,807],{"class":699,"line":806},19,[697,808,743],{"emptyLinePlaceholder":353},[697,810,812],{"class":699,"line":811},20,[697,813,814],{},"# CPU 密集型任務：計算 Fibonacci 數列\n",[697,816,818],{"class":699,"line":817},21,[697,819,820],{},"def fib(n):\n",[697,822,824],{"class":699,"line":823},22,[697,825,826],{},"    if n \u003C= 1:\n",[697,828,830],{"class":699,"line":829},23,[697,831,832],{},"        return n\n",[697,834,836],{"class":699,"line":835},24,[697,837,838],{},"    return fib(n - 1) + fib(n - 2)\n",[697,840,842],{"class":699,"line":841},25,[697,843,743],{"emptyLinePlaceholder":353},[697,845,847],{"class":699,"line":846},26,[697,848,849],{},"# I/O 綁定任務：模擬網路請求（全局函數）\n",[697,851,853],{"class":699,"line":852},27,[697,854,855],{},"def sync_io_task():\n",[697,857,859],{"class":699,"line":858},28,[697,860,861],{},"    time.sleep(1)  # 模擬 1 秒的 I/O 延遲\n",[697,863,865],{"class":699,"line":864},29,[697,866,743],{"emptyLinePlaceholder":353},[697,868,870],{"class":699,"line":869},30,[697,871,872],{},"# 異步 I/O 任務\n",[697,874,876],{"class":699,"line":875},31,[697,877,878],{},"async def io_bound_task():\n",[697,880,882],{"class":699,"line":881},32,[697,883,884],{},"    await asyncio.sleep(1)  # 模擬 1 秒的 I/O 延遲\n",[697,886,888],{"class":699,"line":887},33,[697,889,890],{},"    return \"I/O 任務完成\"\n",[697,892,894],{"class":699,"line":893},34,[697,895,743],{"emptyLinePlaceholder":353},[697,897,899],{"class":699,"line":898},35,[697,900,901],{},"# 多線程實現\n",[697,903,905],{"class":699,"line":904},36,[697,906,907],{},"@timing_decorator\n",[697,909,911],{"class":699,"line":910},37,[697,912,913],{},"def run_multithreading(n_tasks, task_type=\"cpu\"):\n",[697,915,917],{"class":699,"line":916},38,[697,918,919],{},"    threads = []\n",[697,921,923],{"class":699,"line":922},39,[697,924,925],{},"    if task_type == \"cpu\":\n",[697,927,929],{"class":699,"line":928},40,[697,930,931],{},"        for _ in range(n_tasks):\n",[697,933,935],{"class":699,"line":934},41,[697,936,937],{},"            t = threading.Thread(target=fib, args=(35,))\n",[697,939,941],{"class":699,"line":940},42,[697,942,943],{},"            threads.append(t)\n",[697,945,947],{"class":699,"line":946},43,[697,948,949],{},"            t.start()\n",[697,951,953],{"class":699,"line":952},44,[697,954,955],{},"        for t in threads:\n",[697,957,959],{"class":699,"line":958},45,[697,960,961],{},"            t.join()\n",[697,963,965],{"class":699,"line":964},46,[697,966,967],{},"    else:  # I/O 任務\n",[697,969,971],{"class":699,"line":970},47,[697,972,931],{},[697,974,976],{"class":699,"line":975},48,[697,977,978],{},"            t = threading.Thread(target=sync_io_task)\n",[697,980,982],{"class":699,"line":981},49,[697,983,943],{},[697,985,987],{"class":699,"line":986},50,[697,988,949],{},[697,990,992],{"class":699,"line":991},51,[697,993,955],{},[697,995,997],{"class":699,"line":996},52,[697,998,961],{},[697,1000,1002],{"class":699,"line":1001},53,[697,1003,743],{"emptyLinePlaceholder":353},[697,1005,1007],{"class":699,"line":1006},54,[697,1008,1009],{},"# 多進程實現\n",[697,1011,1013],{"class":699,"line":1012},55,[697,1014,907],{},[697,1016,1018],{"class":699,"line":1017},56,[697,1019,1020],{},"def run_multiprocessing(n_tasks, task_type=\"cpu\"):\n",[697,1022,1024],{"class":699,"line":1023},57,[697,1025,1026],{},"    processes = []\n",[697,1028,1030],{"class":699,"line":1029},58,[697,1031,925],{},[697,1033,1035],{"class":699,"line":1034},59,[697,1036,931],{},[697,1038,1040],{"class":699,"line":1039},60,[697,1041,1042],{},"            p = multiprocessing.Process(target=fib, args=(35,))\n",[697,1044,1046],{"class":699,"line":1045},61,[697,1047,1048],{},"            processes.append(p)\n",[697,1050,1052],{"class":699,"line":1051},62,[697,1053,1054],{},"            p.start()\n",[697,1056,1058],{"class":699,"line":1057},63,[697,1059,1060],{},"        for p in processes:\n",[697,1062,1064],{"class":699,"line":1063},64,[697,1065,1066],{},"            p.join()\n",[697,1068,1070],{"class":699,"line":1069},65,[697,1071,967],{},[697,1073,1075],{"class":699,"line":1074},66,[697,1076,931],{},[697,1078,1080],{"class":699,"line":1079},67,[697,1081,1082],{},"            p = multiprocessing.Process(target=sync_io_task)\n",[697,1084,1086],{"class":699,"line":1085},68,[697,1087,1048],{},[697,1089,1091],{"class":699,"line":1090},69,[697,1092,1054],{},[697,1094,1096],{"class":699,"line":1095},70,[697,1097,1060],{},[697,1099,1101],{"class":699,"line":1100},71,[697,1102,1066],{},[697,1104,1106],{"class":699,"line":1105},72,[697,1107,743],{"emptyLinePlaceholder":353},[697,1109,1111],{"class":699,"line":1110},73,[697,1112,1113],{},"# Asyncio 實現\n",[697,1115,1117],{"class":699,"line":1116},74,[697,1118,907],{},[697,1120,1122],{"class":699,"line":1121},75,[697,1123,1124],{},"async def run_asyncio(n_tasks):\n",[697,1126,1128],{"class":699,"line":1127},76,[697,1129,1130],{},"    tasks = [io_bound_task() for _ in range(n_tasks)]\n",[697,1132,1134],{"class":699,"line":1133},77,[697,1135,1136],{},"    await asyncio.gather(*tasks)\n",[697,1138,1140],{"class":699,"line":1139},78,[697,1141,743],{"emptyLinePlaceholder":353},[697,1143,1145],{"class":699,"line":1144},79,[697,1146,1147],{},"# 禁用 GIL 的多線程實現（需 Python 3.13 --disable-gil）\n",[697,1149,1151],{"class":699,"line":1150},80,[697,1152,907],{},[697,1154,1156],{"class":699,"line":1155},81,[697,1157,1158],{},"def run_nogil_multithreading(n_tasks, task_type=\"cpu\"):\n",[697,1160,1162],{"class":699,"line":1161},82,[697,1163,1164],{},"    with ThreadPoolExecutor(max_workers=n_tasks) as executor:\n",[697,1166,1168],{"class":699,"line":1167},83,[697,1169,1170],{},"        if task_type == \"cpu\":\n",[697,1172,1174],{"class":699,"line":1173},84,[697,1175,1176],{},"            futures = [executor.submit(fib, 35) for _ in range(n_tasks)]\n",[697,1178,1180],{"class":699,"line":1179},85,[697,1181,1182],{},"        else:  # I/O 任務\n",[697,1184,1186],{"class":699,"line":1185},86,[697,1187,1188],{},"            futures = [executor.submit(sync_io_task) for _ in range(n_tasks)]\n",[697,1190,1192],{"class":699,"line":1191},87,[697,1193,1194],{},"        for future in futures:\n",[697,1196,1198],{"class":699,"line":1197},88,[697,1199,1200],{},"            future.result()\n",[697,1202,1204],{"class":699,"line":1203},89,[697,1205,743],{"emptyLinePlaceholder":353},[697,1207,1209],{"class":699,"line":1208},90,[697,1210,1211],{},"# 主程式\n",[697,1213,1215],{"class":699,"line":1214},91,[697,1216,1217],{},"if __name__ == \"__main__\":\n",[697,1219,1221],{"class":699,"line":1220},92,[697,1222,1223],{},"    n_tasks = 4  # 任務數量\n",[697,1225,1227],{"class":699,"line":1226},93,[697,1228,743],{"emptyLinePlaceholder":353},[697,1230,1232],{"class":699,"line":1231},94,[697,1233,1234],{},"    print(\"=== CPU 密集型任務 (計算 Fibonacci 數列) ===\")\n",[697,1236,1238],{"class":699,"line":1237},95,[697,1239,1240],{},"    print(\"多線程 (Multithreading):\")\n",[697,1242,1244],{"class":699,"line":1243},96,[697,1245,1246],{},"    run_multithreading(n_tasks, task_type=\"cpu\")\n",[697,1248,1250],{"class":699,"line":1249},97,[697,1251,743],{"emptyLinePlaceholder":353},[697,1253,1255],{"class":699,"line":1254},98,[697,1256,1257],{},"    print(\"\\n多進程 (Multiprocessing):\")\n",[697,1259,1261],{"class":699,"line":1260},99,[697,1262,1263],{},"    run_multiprocessing(n_tasks, task_type=\"cpu\")\n",[697,1265,1267],{"class":699,"line":1266},100,[697,1268,743],{"emptyLinePlaceholder":353},[697,1270,1272],{"class":699,"line":1271},101,[697,1273,1274],{},"    if sys.version_info >= (3, 13) and hasattr(sys, \"disable_gil\"):\n",[697,1276,1278],{"class":699,"line":1277},102,[697,1279,1280],{},"        print(\"\\n禁用 GIL 的多線程:\")\n",[697,1282,1284],{"class":699,"line":1283},103,[697,1285,1286],{},"        run_nogil_multithreading(n_tasks, task_type=\"cpu\")\n",[697,1288,1290],{"class":699,"line":1289},104,[697,1291,1292],{},"    else:\n",[697,1294,1296],{"class":699,"line":1295},105,[697,1297,1298],{},"        print(\"\\n禁用 GIL 的多線程: 需要 Python 3.13 並啟用 --disable-gil\")\n",[697,1300,1302],{"class":699,"line":1301},106,[697,1303,743],{"emptyLinePlaceholder":353},[697,1305,1307],{"class":699,"line":1306},107,[697,1308,1309],{},"    print(\"\\n=== I/O 綁定任務 (模擬網路請求) ===\")\n",[697,1311,1313],{"class":699,"line":1312},108,[697,1314,1240],{},[697,1316,1318],{"class":699,"line":1317},109,[697,1319,1320],{},"    run_multithreading(n_tasks, task_type=\"io\")\n",[697,1322,1324],{"class":699,"line":1323},110,[697,1325,743],{"emptyLinePlaceholder":353},[697,1327,1329],{"class":699,"line":1328},111,[697,1330,1257],{},[697,1332,1334],{"class":699,"line":1333},112,[697,1335,1336],{},"    run_multiprocessing(n_tasks, task_type=\"io\")\n",[697,1338,1340],{"class":699,"line":1339},113,[697,1341,743],{"emptyLinePlaceholder":353},[697,1343,1345],{"class":699,"line":1344},114,[697,1346,1347],{},"    print(\"\\nAsyncio:\")\n",[697,1349,1351],{"class":699,"line":1350},115,[697,1352,1353],{},"    asyncio.run(run_asyncio(n_tasks))\n",[697,1355,1357],{"class":699,"line":1356},116,[697,1358,743],{"emptyLinePlaceholder":353},[697,1360,1362],{"class":699,"line":1361},117,[697,1363,1274],{},[697,1365,1367],{"class":699,"line":1366},118,[697,1368,1280],{},[697,1370,1372],{"class":699,"line":1371},119,[697,1373,1374],{},"        run_nogil_multithreading(n_tasks, task_type=\"io\")\n",[697,1376,1378],{"class":699,"line":1377},120,[697,1379,1292],{},[697,1381,1383],{"class":699,"line":1382},121,[697,1384,1298],{},[23,1386,1387],{"id":1387},"執行結果分析",[689,1389,1393],{"className":1390,"code":1391,"language":1392,"meta":326,"style":326},"language-bash shiki shiki-themes github-light github-dark","$ uv run --no-project --python 3.13.5+freethreaded test.py\n\n=== CPU 密集型任務 (計算 Fibonacci 數列) ===\n多線程 (Multithreading):\nrun_multithreading 執行時間: 0.8912 秒\n\n多進程 (Multiprocessing):\nrun_multiprocessing 執行時間: 1.0846 秒\n\n禁用 GIL 的多線程:\nGIL 狀態: 禁用\nrun_nogil_multithreading 執行時間: 0.8713 秒\n\n=== I/O 綁定任務 (模擬網路請求) ===\n多線程 (Multithreading):\nrun_multithreading 執行時間: 1.0072 秒\n\n多進程 (Multiprocessing):\nrun_multiprocessing 執行時間: 1.1046 秒\n\nAsyncio:\nrun_asyncio 執行時間: 0.0000 秒\n\n禁用 GIL 的多線程:\nGIL 狀態: 禁用\nrun_nogil_multithreading 執行時間: 1.0093 秒\n","bash",[190,1394,1395,1421,1425,1449,1457,1471,1475,1483,1495,1499,1510,1521,1533,1537,1550,1556,1567,1571,1577,1588,1592,1597,1609,1613,1621,1629],{"__ignoreMap":326},[697,1396,1397,1401,1405,1408,1412,1415,1418],{"class":699,"line":700},[697,1398,1400],{"class":1399},"sScJk","$",[697,1402,1404],{"class":1403},"sZZnC"," uv",[697,1406,1407],{"class":1403}," run",[697,1409,1411],{"class":1410},"sj4cs"," --no-project",[697,1413,1414],{"class":1410}," --python",[697,1416,1417],{"class":1403}," 3.13.5+freethreaded",[697,1419,1420],{"class":1403}," test.py\n",[697,1422,1423],{"class":699,"line":327},[697,1424,743],{"emptyLinePlaceholder":353},[697,1426,1427,1430,1433,1436,1440,1443,1446],{"class":699,"line":335},[697,1428,1429],{"class":1403},"===",[697,1431,1432],{"class":1403}," CPU",[697,1434,1435],{"class":1403}," 密集型任務",[697,1437,1439],{"class":1438},"sVt8B"," (計算 ",[697,1441,1442],{"class":1403},"Fibonacci",[697,1444,1445],{"class":1403}," 數列",[697,1447,1448],{"class":1438},") ===\n",[697,1450,1451,1454],{"class":699,"line":716},[697,1452,1453],{"class":1399},"多線程",[697,1455,1456],{"class":1438}," (Multithreading):\n",[697,1458,1459,1462,1465,1468],{"class":699,"line":722},[697,1460,1461],{"class":1399},"run_multithreading",[697,1463,1464],{"class":1403}," 執行時間:",[697,1466,1467],{"class":1410}," 0.8912",[697,1469,1470],{"class":1403}," 秒\n",[697,1472,1473],{"class":699,"line":728},[697,1474,743],{"emptyLinePlaceholder":353},[697,1476,1477,1480],{"class":699,"line":734},[697,1478,1479],{"class":1399},"多進程",[697,1481,1482],{"class":1438}," (Multiprocessing):\n",[697,1484,1485,1488,1490,1493],{"class":699,"line":740},[697,1486,1487],{"class":1399},"run_multiprocessing",[697,1489,1464],{"class":1403},[697,1491,1492],{"class":1410}," 1.0846",[697,1494,1470],{"class":1403},[697,1496,1497],{"class":699,"line":746},[697,1498,743],{"emptyLinePlaceholder":353},[697,1500,1501,1504,1507],{"class":699,"line":752},[697,1502,1503],{"class":1399},"禁用",[697,1505,1506],{"class":1403}," GIL",[697,1508,1509],{"class":1403}," 的多線程:\n",[697,1511,1512,1515,1518],{"class":699,"line":758},[697,1513,1514],{"class":1399},"GIL",[697,1516,1517],{"class":1403}," 狀態:",[697,1519,1520],{"class":1403}," 禁用\n",[697,1522,1523,1526,1528,1531],{"class":699,"line":764},[697,1524,1525],{"class":1399},"run_nogil_multithreading",[697,1527,1464],{"class":1403},[697,1529,1530],{"class":1410}," 0.8713",[697,1532,1470],{"class":1403},[697,1534,1535],{"class":699,"line":770},[697,1536,743],{"emptyLinePlaceholder":353},[697,1538,1539,1541,1544,1547],{"class":699,"line":776},[697,1540,1429],{"class":1403},[697,1542,1543],{"class":1403}," I/O",[697,1545,1546],{"class":1403}," 綁定任務",[697,1548,1549],{"class":1438}," (模擬網路請求) ===\n",[697,1551,1552,1554],{"class":699,"line":782},[697,1553,1453],{"class":1399},[697,1555,1456],{"class":1438},[697,1557,1558,1560,1562,1565],{"class":699,"line":788},[697,1559,1461],{"class":1399},[697,1561,1464],{"class":1403},[697,1563,1564],{"class":1410}," 1.0072",[697,1566,1470],{"class":1403},[697,1568,1569],{"class":699,"line":794},[697,1570,743],{"emptyLinePlaceholder":353},[697,1572,1573,1575],{"class":699,"line":800},[697,1574,1479],{"class":1399},[697,1576,1482],{"class":1438},[697,1578,1579,1581,1583,1586],{"class":699,"line":806},[697,1580,1487],{"class":1399},[697,1582,1464],{"class":1403},[697,1584,1585],{"class":1410}," 1.1046",[697,1587,1470],{"class":1403},[697,1589,1590],{"class":699,"line":811},[697,1591,743],{"emptyLinePlaceholder":353},[697,1593,1594],{"class":699,"line":817},[697,1595,1596],{"class":1399},"Asyncio:\n",[697,1598,1599,1602,1604,1607],{"class":699,"line":823},[697,1600,1601],{"class":1399},"run_asyncio",[697,1603,1464],{"class":1403},[697,1605,1606],{"class":1410}," 0.0000",[697,1608,1470],{"class":1403},[697,1610,1611],{"class":699,"line":829},[697,1612,743],{"emptyLinePlaceholder":353},[697,1614,1615,1617,1619],{"class":699,"line":835},[697,1616,1503],{"class":1399},[697,1618,1506],{"class":1403},[697,1620,1509],{"class":1403},[697,1622,1623,1625,1627],{"class":699,"line":841},[697,1624,1514],{"class":1399},[697,1626,1517],{"class":1403},[697,1628,1520],{"class":1403},[697,1630,1631,1633,1635,1638],{"class":699,"line":846},[697,1632,1525],{"class":1399},[697,1634,1464],{"class":1403},[697,1636,1637],{"class":1410}," 1.0093",[697,1639,1470],{"class":1403},[115,1641,1643],{"id":1642},"cpu-密集型任務計算-fibonacci-數列","CPU 密集型任務（計算 Fibonacci 數列）",[11,1645,1646,1647],{},"執行時間排序：",[15,1648,1649],{},"GIL Disabled (0.8713 秒) \u003C 多線程 (0.8912 秒) \u003C 多進程 (1.0846 秒)",[144,1651,1652,1657,1662],{},[71,1653,1654,1656],{},[15,1655,1453],{},"：受 GIL 限制，執行速度與單 CPU 執行差不多",[71,1658,1659,1661],{},[15,1660,1479],{},"：運用多個 CPU 核心加速",[71,1663,1664,1667],{},[15,1665,1666],{},"GIL Disabled","：運用多個 CPU 核心加速，且避免了多進程管理的額外開銷",[115,1669,1671],{"id":1670},"io-綁定任務模擬網路請求","I/O 綁定任務（模擬網路請求）",[11,1673,1646,1674],{},[15,1675,1676],{},"Asyncio (0.0000 秒) \u003C\u003C 多線程 (1.0072 秒) ≈ GIL Disabled (1.0093 秒) ≈ 多進程 (1.1046 秒)",[144,1678,1679,1685],{},[71,1680,1681,1684],{},[15,1682,1683],{},"多線程、多進程、GIL Disabled","：三者效能差不多",[71,1686,1687,1690,1691,1694],{},[15,1688,1689],{},"Asyncio","：效能最好，因為測試任務使用 ",[190,1692,1693],{},"await asyncio.sleep","，基本上不會有運行時間開銷",[23,1696,1697],{"id":1697},"實際應用場景",[11,1699,1700],{},[15,1701,1702],{},"首先需要考慮業務場景，做這個優化加速是否有需要？如果加速沒有很重要的話就是一個 Nice to have 的優化。",[115,1704,1706],{"id":1705},"不建議使用-disabled-gil","不建議使用 Disabled GIL",[11,1708,1709],{},"目前 Disabled GIL 還在測試階段，許多套件都還沒完全支援，也需要自己處理變數管理等問題，目前不考慮使用。",[115,1711,1713],{"id":1712},"適合使用-multiprocessing-的場景","適合使用 Multiprocessing 的場景",[11,1715,1716],{},"非 AI 的大量運算需求，可以使用 Multiprocessing 來加速：",[144,1718,1719,1725],{},[71,1720,1721,1724],{},[15,1722,1723],{},"售電平台的最佳參數求取","：目前策略使用網格搜索，可以切分網格分配給 CPU 執行",[71,1726,1727,1730],{},[15,1728,1729],{},"EV 管理平台","：需要定時計算電站使用率",[115,1732,1734],{"id":1733},"適合使用-asyncio-的場景","適合使用 Asyncio 的場景",[11,1736,1737],{},"網路的大量需求，可以使用 Asyncio 來加速：",[144,1739,1740,1746,1764,1774],{},[71,1741,1742,1745],{},[15,1743,1744],{},"MQTT / OCPP","：這類 pub/sub 協議",[71,1747,1748,490,1751],{},[15,1749,1750],{},"爬蟲或大量 Third-party API 請求",[144,1752,1753],{},[71,1754,1755,1756,1759,1760,1763],{},"使用 ",[190,1757,1758],{},"aiohttp"," 替換 ",[190,1761,1762],{},"requests"," 模組",[71,1765,1766,490,1769],{},[15,1767,1768],{},"Database 異步操作",[144,1770,1771],{},[71,1772,1773],{},"pymongo 遷移到 async client (≥ v4.13)",[71,1775,1776,490,1779],{},[15,1777,1778],{},"Web Framework",[144,1780,1781],{},[71,1782,1783],{},"Flask 遷移到 FastAPI",[23,1785,1786],{"id":1786},"參考資料",[144,1788,1789,1796,1803],{},[71,1790,1791],{},[41,1792,1795],{"href":1793,"rel":1794},"https://www.youtube.com/watch?v=brYsDi-JajI",[45],"【python】asyncio的理解與入門，搞不明白協程？看這個視頻就夠了",[71,1797,1798],{},[41,1799,1802],{"href":1800,"rel":1801},"https://www.youtube.com/watch?v=K0BjgYZbgfE&t=94s",[45],"【python】await機制詳解。再來個硬核內容，把並行和依賴背後的原理全給你講明白",[71,1804,1805],{},[41,1806,1809],{"href":1807,"rel":1808},"https://pymongo.readthedocs.io/en/stable/async-tutorial.html",[45],"Async Tutorial - PyMongo 4.14.1 documentation",[1811,1812,1813],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":326,"searchDepth":327,"depth":327,"links":1815},[1816,1817,1823,1824,1825,1829,1834],{"id":374,"depth":327,"text":375},{"id":384,"depth":327,"text":384,"children":1818},[1819,1820,1821,1822],{"id":387,"depth":335,"text":388},{"id":438,"depth":335,"text":439},{"id":477,"depth":335,"text":478},{"id":514,"depth":335,"text":515},{"id":536,"depth":327,"text":536},{"id":687,"depth":327,"text":687},{"id":1387,"depth":327,"text":1387,"children":1826},[1827,1828],{"id":1642,"depth":335,"text":1643},{"id":1670,"depth":335,"text":1671},{"id":1697,"depth":327,"text":1697,"children":1830},[1831,1832,1833],{"id":1705,"depth":335,"text":1706},{"id":1712,"depth":335,"text":1713},{"id":1733,"depth":335,"text":1734},{"id":1786,"depth":327,"text":1786},"2025-10-24","介紹 Python 並發處理方法，包括多線程、多進程、asyncio 以及其實務應用。",{},"/blog/concurrency",{"title":369,"description":1836},"blog/concurrency",[1842,1843,1844,1689],"Python","Concurrency","Threading","1DEoTJ_oFj-_n1U7PDKbn7wPsTmsBUK-5vAp6nZ_s0E",{"id":1847,"title":1848,"author":6,"body":1849,"category":346,"date":2074,"description":2075,"draft":349,"extension":350,"image":2076,"meta":2077,"navigation":353,"path":2078,"seo":2079,"stem":2080,"tags":2081,"__hash__":2084},"blog/blog/decrease-coding-agent-illusion.md","如何降低 Coding Agent的幻覺？",{"type":8,"value":1850,"toc":2061},[1851,1855,1858,1861,1865,1872,1879,1882,1885,1888,1900,1903,1906,1909,1912,1920,1923,1929,1934,1938,1941,1949,1954,1960,1963,1967,1974,1985,1993,1997,2004,2009,2017,2020,2027,2033,2036,2042,2045,2050],[1852,1853,1854],"h1",{"id":1854},"前言",[11,1856,1857],{},"在做公司 POC 的過程，因為需要用到 Strands Agent & AWS AgentCore 一些比較新的SDK，實在有太多次都遇到 AI Gen 完以後發現 Syntax Highlight 沒有提示，看一下 Source Code or Docs 發現根本沒有這個 function / attr 的狀況，嘗試了幾個提升 LLM 準確率的方法",[11,1859,1860],{},"基本上解決思路都是讓 Agent 可以有個參照對象，提升正確率",[23,1862,1864],{"id":1863},"context7","Context7",[11,1866,1867],{},[41,1868,1871],{"href":1869,"rel":1870},"https://github.com/upstash/context7",[45],"GitHub - upstash/context7: Context7 MCP Server -- Up-to-date code documentation for LLMs and AI code editors",[11,1873,1874],{},[41,1875,1878],{"href":1876,"rel":1877},"https://context7.com/",[45],"Context7 - Up-to-date documentation for LLMs and AI code editors",[11,1880,1881],{},"Context7 是一個 MCP Tool, 可以自動查詢最新文檔",[115,1883,1884],{"id":1884},"文檔來源",[11,1886,1887],{},"任何人都可以到官網去發一個 Add Library Request，這邊可以看到目前正在進行 Parsing & Crawling 的目標文檔，我嘗試把我自己的repo丟上去也可以跑，並且有辦法在 Dashboard 搜尋到",[11,1889,1890,1894,1897],{},[1891,1892],"img",{"alt":326,"src":1893},"/images/blog/decrease-coding-agent-illusion/image1.png",[1891,1895],{"alt":326,"src":1896},"/images/blog/decrease-coding-agent-illusion/image2.png",[1891,1898],{"alt":326,"src":1899},"/images/blog/decrease-coding-agent-illusion/image3.png",[115,1901,1902],{"id":1902},"使用",[11,1904,1905],{},"可以選擇自架 MCP Server or 使用官方服務",[11,1907,1908],{},"原本因為方便所以直接使用官方服務(安裝時需填入 API key)，一個月限制 1000 次 query，實際使用發現他好像每天都會重置 1000 次的 quota，基本上用不完。",[11,1910,1911],{},"你可以選擇加敘述在會自動放到 Context 的地方 (ex: cursor rule, claude.md, agent.md, etc.)",[689,1913,1918],{"className":1914,"code":1916,"language":1917},[1915],"language-text","Always use Context7 MCP when I need library/API documentation, code generation, setup or configuration steps without me having to explicitly ask.\n","text",[190,1919,1916],{"__ignoreMap":326},[11,1921,1922],{},"或者加在 LLM 來回的地方",[689,1924,1927],{"className":1925,"code":1926,"language":1917},[1915],"幫我寫一個 strands agent graph pattern example, 記得遵照文檔教學執行/必須使用 context 7...\n",[190,1928,1926],{"__ignoreMap":326},[11,1930,1931],{},[1891,1932],{"alt":326,"src":1933},"/images/blog/decrease-coding-agent-illusion/image4.png",[115,1935,1937],{"id":1936},"how-it-works","How it works?",[11,1939,1940],{},"使用兩個 MCP Tools 來實現",[144,1942,1943,1946],{},[71,1944,1945],{},"Search",[71,1947,1948],{},"Get Context",[1950,1951,1953],"h4",{"id":1952},"context-usage","Context Usage",[689,1955,1958],{"className":1956,"code":1957,"language":1917},[1915],"MCP tools · /mcp                                                                                                                                                   \n     └ mcp__context7__resolve-library-id: 499 tokens                                                                                                                    \n     └ mcp__context7__query-docs: 408 tokens             \n",[190,1959,1957],{"__ignoreMap":326},[11,1961,1962],{},"可以看到 context7在 context 使用上算是非常輕量的 MCP Tool",[115,1964,1966],{"id":1965},"context7-作為-skill-管理工具","Context7 作為 Skill 管理工具",[11,1968,1969],{},[41,1970,1973],{"href":1971,"rel":1972},"https://context7.com/docs/skills",[45],"Skills - Context7 MCP",[144,1975,1976,1979,1982],{},[71,1977,1978],{},"搜尋功能",[71,1980,1981],{},"號稱有濾除有安全疑慮的 Skill (不安全的 script / prompt injection…)",[71,1983,1984],{},"可以自動偵測本機上有安裝的 Coding LLM 然後安裝進去 (但是看起來不支援 Kiro🥲)",[11,1986,1987,1990],{},[1891,1988],{"alt":326,"src":1989},"/images/blog/decrease-coding-agent-illusion/image5.png",[1891,1991],{"alt":326,"src":1992},"/images/blog/decrease-coding-agent-illusion/image6.png",[23,1994,1996],{"id":1995},"skill","Skill",[11,1998,1999],{},[41,2000,2003],{"href":2001,"rel":2002},"https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview",[45],"Agent Skills",[98,2005,2006],{},[11,2007,2008],{},"大家應該都知道的東西，網路上很多基本介紹這邊不多贅述，我的用法是把docs repo 直接放到 Reference 內，讓 LLM 去產生 SKILL.md",[144,2010,2011,2014],{},[71,2012,2013],{},"讓 LLM 知道有這個 skill",[71,2015,2016],{},"不一定每個 sdk 都有 docs repo, 所以也順便有個 index 可以讓 LLM 快速的查詢文檔路徑",[115,2018,2019],{"id":2019},"範例",[11,2021,2022],{},[41,2023,2026],{"href":2024,"rel":2025},"https://github.com/strands-agents/docs",[45],"GitHub - strands-agents/docs: Documentation for the Strands Agents SDK. A model-driven approach to building AI agents in just a few lines of code.",[689,2028,2031],{"className":2029,"code":2030,"language":1917},[1915],"# ~/.claude/skills/strands-agents-docs/SKILL.md\n---\nname: strands-agents-docs\ndescription: Access comprehensive Strands Agents documentation to help build, deploy, and operate AI agents using the Strands Agents SDK\n---\n# Strands Agents Documentation Skill\nThis skill provides access to the complete Strands Agents documentation, enabling code agents to quickly locate relevant guides, examples, and API references for building AI agents with the Strands Agents SDK.\n## Instructions\nWhen working with Strands Agents SDK, use this skill to:\n1. Locate relevant documentation files based on the task or concept\n2. Reference specific guides for implementation patterns\n3. Find deployment and production operation best practices\n4. Access model provider configurations and examples\n5. Understand multi-agent patterns and tool development\nSearch for documentation by topic or concept, and reference the appropriate markdown file path below for detailed information.\n## Documentation Index\n### Quickstart Guides\n- `/Users/ting/.claude/skills/strands-agents-docs/references/docs/user-guide/quickstart.md` - Complete quickstart guide showing how to create your first Strands agent with tools and model providers\n- `/Users/ting/.claude/skills/strands-agents-docs/references/docs/user-guide/quickstart/overview.md` - Overview of getting started with Strands Agents\n=== 下略 ===\n",[190,2032,2030],{"__ignoreMap":326},[115,2034,1953],{"id":2035},"context-usage-1",[689,2037,2040],{"className":2038,"code":2039,"language":1917},[1915],"Skills · /skills\n User\n └ bedrock-agentcore-sdk: 38 tokens                                                                                                                                 \n └ strands-agents-docs: 36 tokens\n",[190,2041,2039],{"__ignoreMap":326},[23,2043,2044],{"id":2044},"其他",[98,2046,2047],{},[11,2048,2049],{},"基本上都是“LLM已經拉了一坨沒辦法跑的 Code”的時候，已經參與Debug了，是不理想的狀況",[144,2051,2052,2055,2058],{},[71,2053,2054],{},"指出 site-packages 內的原始碼路徑給 LLM, 讓他參照使用",[71,2056,2057],{},"複製文檔直接喂到嘴邊",[71,2059,2060],{},"搭配其他 AI Tools (Perplexity, Deepwiki)",{"title":326,"searchDepth":327,"depth":327,"links":2062},[2063,2069,2073],{"id":1863,"depth":327,"text":1864,"children":2064},[2065,2066,2067,2068],{"id":1884,"depth":335,"text":1884},{"id":1902,"depth":335,"text":1902},{"id":1936,"depth":335,"text":1937},{"id":1965,"depth":335,"text":1966},{"id":1995,"depth":327,"text":1996,"children":2070},[2071,2072],{"id":2019,"depth":335,"text":2019},{"id":2035,"depth":335,"text":1953},{"id":2044,"depth":327,"text":2044},"2026-01-26","介紹透過 context7 & agent skills 來提升 Coding agent one shot 機率的方法","/images/blog/decrease-coding-agent-illusion/banner.png",{},"/blog/decrease-coding-agent-illusion",{"title":1848,"description":2075},"blog/decrease-coding-agent-illusion",[2082,2083],"Tooling","Development","m_26ovdfaN8lhTUGpa0GYVOveveCALhEyBRKj-NqpLs",{"id":2086,"title":2087,"author":6,"body":2088,"category":346,"date":1835,"description":2472,"draft":349,"extension":350,"image":326,"meta":2473,"navigation":353,"path":2474,"seo":2475,"stem":2476,"tags":2477,"__hash__":2478},"blog/blog/python-gil-introduction.md","Python GIL 介紹",{"type":8,"value":2089,"toc":2460},[2090,2094,2099,2102,2122,2125,2129,2134,2138,2158,2162,2165,2240,2244,2247,2315,2319,2322,2346,2349,2369,2372,2428,2430],[23,2091,2093],{"id":2092},"什麼是-gil","什麼是 GIL？",[98,2095,2096],{},[11,2097,2098],{},"💡 GIL 是 CPython 解釋器中的一個鎖，確保在任何時刻只有一個線程可以執行 Python 字節碼。",[11,2100,2101],{},"這意味著即使有多個線程，Python 程式也無法真正利用多核心 CPU 實現並行（parallelism），僅能實現並發（concurrency）的假象。GIL 為 Python 提供了以下好處：",[144,2103,2104,2110,2116],{},[71,2105,2106,2109],{},[15,2107,2108],{},"簡化種族條件（Race Conditions）","：防止Multi thread同時修改共享資料，降低記憶體損壞風險。",[71,2111,2112,2115],{},[15,2113,2114],{},"簡化垃圾回收（Garbage Collection）","：GIL 使記憶體管理更簡單，無需複雜的鎖機制。",[71,2117,2118,2121],{},[15,2119,2120],{},"歷史背景","：Python 於 1991 年設計時，多數電腦僅有單核心 CPU，GIL 是當時簡化實現的合理選擇。",[11,2123,2124],{},"然而，GIL 的缺點顯而易見：它限制了多核心 CPU 的利用率，使 Python 在 CPU 密集型任務（如數學計算、資料解析、AI 模型訓練）上的效能不如預期。",[23,2126,2128],{"id":2127},"為什麼移除-gilpep-703-python-313","為什麼移除 GIL？（PEP 703, Python 3.13）",[98,2130,2131],{},[11,2132,2133],{},"💡 隨著硬體技術的進步（多核心 CPU 普及）和 Python 社群對高效能的需求，GIL 逐漸成為瓶頸。PEP 703（Python 3.13）提出使 GIL 可選，允許程式在編譯時或運行時禁用 GIL，讓Multi thread直接利用操作系統的線程調度器，實現真正的並行。",[115,2135,2137],{"id":2136},"移除-gil-的動機","移除 GIL 的動機",[144,2139,2140,2146,2152],{},[71,2141,2142,2145],{},[15,2143,2144],{},"社群需求","：開發者希望 Python 能更快，並充分利用現代多核心硬體。",[71,2147,2148,2151],{},[15,2149,2150],{},"效能提升","：禁用 GIL 後，某些 CPU 密集型任務（如桶排序、分形生成）可顯著加速。",[71,2153,2154,2157],{},[15,2155,2156],{},"競爭壓力","：其他語言（如 Go、Rust）支援真正的並行，Python 需跟上時代。",[115,2159,2161],{"id":2160},"移除-gil-的挑戰","移除 GIL 的挑戰",[11,2163,2164],{},"移除 GIL 並非易事，因為 Python 的許多核心機制依賴 GIL 的保護。以下是主要挑戰：",[68,2166,2167,2199,2211,2228],{},[71,2168,2169,2172],{},[15,2170,2171],{},"引用計數（Reference Counting）",[144,2173,2174,2180],{},[71,2175,2176,2179],{},[15,2177,2178],{},"問題","：傳統的非原子引用計數（non-atomic reference counting）不具線程安全，可能導致種族條件。例如，refcount++ 分三步（讀、加、寫），可能被其他線程中斷。",[71,2181,2182,490,2185],{},[15,2183,2184],{},"解決方案",[144,2186,2187,2193],{},[71,2188,2189,2192],{},[15,2190,2191],{},"原子引用計數","：線程安全，但速度慢 10x-100x。",[71,2194,2195,2198],{},[15,2196,2197],{},"偏向引用計數（Biased Reference Counting）","：檢查引用是否僅屬於單一線程，若是則使用快速的非原子計數，否則使用原子計數。",[71,2200,2201,2204],{},[15,2202,2203],{},"垃圾回收（Garbage Collection）",[144,2205,2206],{},[71,2207,2208,2210],{},[15,2209,2178],{},"：傳統垃圾回收依賴 GIL 保護，需改用延遲引用計數（deferred reference counting）來處理循環引用。",[71,2212,2213,2216],{},[15,2214,2215],{},"記憶體分配",[144,2217,2218,2223],{},[71,2219,2220,2222],{},[15,2221,2178],{},"：現有記憶體分配器假設 GIL 保護，不具線程安全。",[71,2224,2225,2227],{},[15,2226,2184],{},"：開發新的線程安全記憶體分配器，優化列表和字典的快速讀取。",[71,2229,2230,2233],{},[15,2231,2232],{},"兼容性",[144,2234,2235],{},[71,2236,2237,2239],{},[15,2238,2178],{},"：許多 C-API 擴展（如 NumPy、Pandas）假設 GIL 存在，需重新編譯以支援無 GIL 環境。",[23,2241,2243],{"id":2242},"gil-與禁用-gil-的比較","GIL 與禁用 GIL 的比較",[11,2245,2246],{},"以下表格比較了 GIL 和禁用 GIL 的特點：",[538,2248,2249,2261],{},[541,2250,2251],{},[544,2252,2253,2255,2258],{},[547,2254,549],{},[547,2256,2257],{},"啟用 GIL",[547,2259,2260],{},"禁用 GIL",[563,2262,2263,2276,2289,2302],{},[544,2264,2265,2270,2273],{},[568,2266,2267],{},[15,2268,2269],{},"並行性",[568,2271,2272],{},"非真正的並行，僅一個線程執行",[568,2274,2275],{},"真正的Multi thread並行，利用多核心",[544,2277,2278,2283,2286],{},[568,2279,2280],{},[15,2281,2282],{},"資料共享",[568,2284,2285],{},"簡單，無需額外鎖",[568,2287,2288],{},"需小心處理種族條件（如使用 threading.Lock）",[544,2290,2291,2296,2299],{},[568,2292,2293],{},[15,2294,2295],{},"效能",[568,2297,2298],{},"受限於 GIL，CPU 綁定任務慢",[568,2300,2301],{},"視程式而定，可能顯著提升（如桶排序、分形生成）",[544,2303,2304,2309,2312],{},[568,2305,2306],{},[15,2307,2308],{},"擴展相容性",[568,2310,2311],{},"廣泛支援",[568,2313,2314],{},"需檢查擴展版本（如 Cython、NumPy）",[23,2316,2318],{"id":2317},"禁用-gil-的推薦場景","禁用 GIL 的推薦場景",[11,2320,2321],{},"禁用 GIL 在以下場景中特別有用：",[144,2323,2324,2330,2335,2340],{},[71,2325,2326,2329],{},[15,2327,2328],{},"ETL 處理","：資料提取、轉換和載入需要大量計算。",[71,2331,2332,2334],{},[15,2333,461],{},"：如濾波、轉換等 CPU 密集型操作。",[71,2336,2337,2339],{},[15,2338,464],{},"：處理大量資料並進行模式匹配。",[71,2341,2342,2345],{},[15,2343,2344],{},"即時分析","：需要快速響應的計算任務。",[23,2347,2348],{"id":2348},"注意事項",[144,2350,2351,2357,2363],{},[71,2352,2353,2356],{},[15,2354,2355],{},"Race Condition","：禁用 GIL 後，Multi thread可能同時存取共享資料，導致記憶體損壞。建議使用 threading.Lock 或其他同步機制。",[71,2358,2359,2362],{},[15,2360,2361],{},"擴展模組相容性","：確認使用的庫（如 NumPy、Pandas、PyTorch）支援無 GIL 環境。",[71,2364,2365,2368],{},[15,2366,2367],{},"效能不確定性","：禁用 GIL 不保證所有程式都變快，需針對具體任務進行基準測試。",[23,2370,2371],{"id":2371},"常見誤解與解答",[68,2373,2374,2388,2398,2408,2418],{},[71,2375,2376,2379,2380],{},[15,2377,2378],{},"並發(Concurrency)與並行(Parallelism)的區別","：",[144,2381,2382,2385],{},[71,2383,2384],{},"並發是多任務「看似」同時進行，實際上可能是切換執行。",[71,2386,2387],{},"並行是多任務在多核心上真正同時執行。",[71,2389,2390,2393],{},[15,2391,2392],{},"為什麼 Python 慢？",[144,2394,2395],{},[71,2396,2397],{},"GIL 限制了Multi thread的並行性，導致 CPU 綁定任務無法充分利用多核心。",[71,2399,2400,2403],{},[15,2401,2402],{},"禁用 GIL 如何管理 CPU 使用？",[144,2404,2405],{},[71,2406,2407],{},"透過操作系統的線程調度器，讓Multi thread在多核心上並行執行。",[71,2409,2410,2413],{},[15,2411,2412],{},"禁用 GIL 是否總是更快？",[144,2414,2415],{},[71,2416,2417],{},"不一定，效能提升取決於任務類型和程式設計。某些任務（如 I/O 綁定）可能無明顯改善。",[71,2419,2420,2423],{},[15,2421,2422],{},"簡單資料共享是什麼？",[144,2424,2425],{},[71,2426,2427],{},"指線程間直接存取記憶體的能力，而Multi process需要管道或共享記憶體，較為複雜。",[23,2429,1786],{"id":1786},[144,2431,2432,2439,2446,2453],{},[71,2433,2434],{},[41,2435,2438],{"href":2436,"rel":2437},"https://peps.python.org/pep-0703/",[45],"PEP 703 – Making the Global Interpreter Lock Optional in CPython",[71,2440,2441],{},[41,2442,2445],{"href":2443,"rel":2444},"https://tw.pycon.org/2025/zh-hant/conference/keynotes#Donghee_Na",[45],"PyCon TW 2025 主題演講",[71,2447,2448],{},[41,2449,2452],{"href":2450,"rel":2451},"https://tw.pycon.org/2025/zh-hant/conference/talk/352",[45],"PyCon TW 2025 - Talk 352",[71,2454,2455],{},[41,2456,2459],{"href":2457,"rel":2458},"https://tw.pycon.org/2025/zh-hant/conference/talk/335",[45],"PyCon TW 2025 - Talk 335",{"title":326,"searchDepth":327,"depth":327,"links":2461},[2462,2463,2467,2468,2469,2470,2471],{"id":2092,"depth":327,"text":2093},{"id":2127,"depth":327,"text":2128,"children":2464},[2465,2466],{"id":2136,"depth":335,"text":2137},{"id":2160,"depth":335,"text":2161},{"id":2242,"depth":327,"text":2243},{"id":2317,"depth":327,"text":2318},{"id":2348,"depth":327,"text":2348},{"id":2371,"depth":327,"text":2371},{"id":1786,"depth":327,"text":1786},"Python 全域直譯器鎖（GIL）介紹",{},"/blog/python-gil-introduction",{"title":2087,"description":2472},"blog/python-gil-introduction",[1842,1514,1844,1843],"HEyyMIX4ERxJ70UGu2zKfrzTPLf2cYOCJfUly7xneRo",1774237782408]