--- ### [python - speed up] - [[python - speed up]利用Concurrency加速你的 Python 程式執行效率](https://hackmd.io/@YungHuiHsu/SJ5EgB5eT) - [[python - speed up] process(程序/進程) 與 thread (執行緒/線程)](https://hackmd.io/@YungHuiHsu/SJCIdO5x6) - [[python - speed up] 多執行緒(multi-threading)的基本概念](https://hackmd.io/@YungHuiHsu/r1C9Akpgp) - [python - speed up] threading 模組的使用(待補) - [[python - speed up] How to speed up multiple camera streams simultaneously with multithreading<br>如何使用多執行序加速視訊(相機/錄影)串流](https://hackmd.io/@YungHuiHsu/BJr5SyYQn) - [python - speed up] multiprocessing模組的各種使用方法(待補) - [[python - speed up] multiprocessing模組的Pool功能使用範例。multiprocessing.Pool Sample Notes](https://hackmd.io/@YungHuiHsu/BJiMZLKxp) --- ## 什麼是多執行緒(multi-threading)? 多執行緒是一種允許並行concurrent (同步simultaneous) 執行程式的兩個或多個部分以最大程度地利用 CPU 的技術。作為一個非常基本的範例,多執行緒允許您在一個程式中編寫程式碼並在另一個程式中聽音樂。電腦程式(Programs)由程序(processes)和執行緒(thread)組成。你可以這樣想: * 程式(program)是可執行文件,例如 chrome.exe * 程序(processes)是程式的執行實例。當雙擊電腦上的 Google Chrome 圖示時,會啟動執行 Google Chrome 程式的程序(process)。 * 執行緒(thread)是程序(processes)的最小可執行單元 * 一個程序可以有多個執行緒,其中一個主執行緒。在範例中,單一執行緒可能會顯示您所在的目前網頁tab,而不同的執行緒可能會顯示另一個網頁tab。 執行緒可以給人一種多工處理的錯覺,即使在任何給定時間點 CPU 只執行一個執行緒。每個執行緒都會在 CPU 上獲得一段時間,然後被切換出去。 ### 為什麼要使用多執行緒? 隨著多核心的引入,多執行緒對於應用程式的效率變得極為重要。使用多個執行緒和單一核心,您的應用程式必須來回轉換才能產生多工的錯覺。 借助多個內核,應用程式可以利用底層硬體透過專用內核運行各個執行序,從而使應用程式響應更快、更有效率。多執行緒基本上可以充分利用 CPU 和多個內核,這樣就不會因為內核閒置而無法利用處理能力。 使用多執行緒有以下幾個優點: * 更高的吞吐量 * 響應式應用程式給人一種多工處理的錯覺。 * 資源的有效利用。與產生全新程序相比,執行緒建立是輕量級的,對於在處理 Web 請求時使用執行緒而不是建立新程序的 Web 伺服器來說,消耗的資源要少得多。 ## 多執行緒(multi-threading)的基本概念 ### 並行Concurrency * 並行性是程式同時處理(而不是執行)許多事情的能力,指程式架構,將程式拆開成多個可獨立運作的工作。 * 不要將並行性與平行性混淆,平行性(Parallelism)指程式執行,指同時執行許多操作。 進一步比較見[[Python] Concurrency(並行)和Parallelism(平行)](https://hackmd.io/@YungHuiHsu/SJ5EgB5eT) ### 切換 Context Switching Context Switching 是指作業系統將 CPU 的注意力從一個processes/thread轉移到另一個processes/thread的過程。在這個過程中,系統會保存當前processes/thread的狀態(稱為“上下文”)並恢復另一個processes/thread的狀態,以便可以從上次停止的地方繼續執行。 > 在電腦科學中,任務(task)的上下文(英語:context)是一個任務所必不可少的一組資料(該任務可以是行程、執行緒)。這些資料允許任務中斷,在這之後仍可在同一個地方繼續執行。上下文的這一概念在中斷的任務的場景下具有重大意義,其中,任務在被中斷之後,處理器儲存上下文並提供中斷處理(interrupt service routine)。因此,上下文越小,延遲越小。 > 上下文的資料可能存放於處理器暫存器、任務所利用的記憶體、某些作業系統管理的任務所使用的控制暫存器(control registers)。 -wiki 在多任務系統中,通常有多個processes/thread需要 CPU 的時間來執行。由於 CPU 在同一時間只能執行一個任務,因此系統需要一種機制來管理這些processes/thread的執行。通過 Context Switching,系統可以確保每個processes/thread都能得到適當的 CPU 時間,並且系統資源得到合理的分配。 ![](https://hackmd.io/_uploads/SJJqRepea.png =600x) [source: multitasking-and-context-switching](https://www.bryanbraun.com/2012/06/25/multitasking-and-context-switching/) ### 執行緒池 Thread Pools #### 什麼是 Thread Pools? Thread Pools是一個包含預先創建的執行緒集合的池。當一個新的任務到來時,從池中取出一個執行緒來執行任務,而不是現場創建一個新的執行緒。一旦任務完成,這個執行緒將返回池中,等待下一個任務的分配。 #### 為什麼使用 Thread Pools? * 效能提升:創建和銷毀執行緒會消耗系統資源和時間。通過重用已經創建的執行緒,我們可以節省這部分的開銷。 * 資源管理:執行緒池允許我們限制系統中同時運行的執行緒數量,從而有效管理系統資源。 * 提高穩定性:限制同時運行的執行緒數量可以防止資源過度使用,並確保系統穩定運行。 ### 鎖 Lock #### 定義 在多執行緒(Multithreading)環境中,鎖(Lock) 是一種同步機制,用於確保多個執行緒不會同時訪問共享資源或區段(Critical Section),從而避免數據不一致和其他與並行相關的問題。 ![](https://hackmd.io/_uploads/H1lod4TeT.png =500x) [source: 2023。Shekh Ali。Thread Locking ](https://www.shekhali.com/thread-lock-statement-csharp/) :::info **關鍵區段 (Critical Section)** "Critical Section" 指的是一個程式碼區段,其中它可以訪問和修改共享資源,並且一次只能由一個執行緒thread(或程序process)執行。換句話說,當一個執行緒進入關鍵區段時,其他訪問該區段的執行緒必須等待,以達到下列目的: - 數據一致性:確保共享資源在任何時候只被一個執行緒修改,以防止數據不一致或競爭狀態。 - 同步控制:通過控制對共享資源的訪問,確保數據的完整性和一致性。 Critical Section具有下列特性 * 互斥訪問:關鍵區段的代碼在同一時間只能由一個執行緒執行。 * 共享資源保護:它保護共享資源不會被多個執行緒同時訪問和修改。 為了提高程式設計的並行性(Concurency),應該盡可能減小關鍵區段的大小。 ::: #### 重要性 * 數據一致性:鎖可以確保在任何時刻只有一個執行緒能夠訪問特定的資源或區段,確保數據的完整性和一致性。 * 避免競爭狀態:通過控制資源的訪問,鎖有助於防止多個執行緒同時讀寫資料,從而避免競爭狀態(Race Condition)。 * 同步協作:鎖也可以用於協調多個執行緒的執行順序,確保它們以正確的方式協同工作。 #### 功能 * 獲取鎖:當一個執行緒嘗試訪問共享資源或區段時,它必須首先獲取鎖。 * 釋放鎖:當執行緒完成對共享資源的訪問後,它必須釋放鎖,以便其他執行緒可以獲取鎖。 * 阻塞/等待:如果鎖已被其他執行緒獲取,則試圖獲取鎖的執行緒將被阻塞(或進入等待狀態),直到鎖變為可用為止。 #### 常見的鎖定機制 1. 二元鎖(Binary Locks) - 互斥鎖Mutex(Mutual Exclusion Lock): - Mutex 是一種確保同一時間只有一個執行緒訪問共享資源的機制。當一個執行緒獲取 Mutex,其他試圖獲取該 Mutex 的執行緒將被阻塞,直到原執行緒釋放該 Mutex。 2. 讀寫鎖(Read-Write Locks) 允許多個執行緒同時讀取資料,但在寫入時,只允許一個執行緒進行寫操作,並阻塞其他所有的讀/寫操作。 3. 自旋鎖(Spinlock) 當執行緒無法獲取鎖時,它將不斷在一個迴圈中檢查鎖的狀態(即“自旋”),這通常用於等待時間預期非常短的情況。 ### 執行緒安全性 Thread Safety 執行緒安全性是一個概念,意味著不同的執行緒可以存取相同的資源,而不會暴露錯誤行為或產生不可預測的結果(例如競爭條件或死鎖)。執行序安全可以透過使用各種同步技術來實現。 ## 多執行緒涉及的問題 ### 死鎖(Deadlock) 當兩個或多個執行緒互相等待對方釋放鎖時,就會發生死鎖。這通常是由於設計不當造成的,需要通過各種策略(例如鎖定時間限制或鎖定順序)來避免。 ![](https://hackmd.io/_uploads/SkSJAmaxp.png =300x) [source: How to Generate Java Deadlock Programmatically and How to Analyze Deadlock](https://crunchify.com/how-to-generate-java-deadlock-programmatically-and-how-to-analyze-deadlock/) ### 競爭危害/競爭條件(Race hazard/Race conditions) 假設現在有一個函式`count += 1`,將同一個全域變數加1,如果分配給兩個執行序thread執行會得到時麼結果呢? - 按序列執行(左圖) - 理想狀態下按照順序執行,得到的預期結果會是2 - 同步執行(右圖) - 如果兩個thread在沒有鎖定或通過號誌同步的情況下同時執行,可能會得到非預期結果 - 在這種情況下,因為執行緒的增加操作沒有互斥,變數同時被寫入為1,導致最終結果為1,而不是預期的2。 | 按序列執行 | 同步執行 | |:---------------------------------------------------:|:---------------------------------------------------:| | ![](https://hackmd.io/_uploads/H1KGY7pxa.png =300x) | ![](https://hackmd.io/_uploads/ByRQY76gp.png =300x) | [source: wiki/Race_condition](https://en.wikipedia.org/wiki/Race_condition) > wiki : > 旨在描述一個系統或者程序的輸出依賴於不受控制的事件出現順序或者出現時機。此詞源自於兩個訊號試著彼此競爭,來影響誰先輸出。 > > 舉例來說,如果電腦中的兩個行程同時試圖修改一個共享記憶體的內容,在沒有並行控制的情況下,最後的結果依賴於兩個行程的執行順序與時機。而且如果發生了並行訪問衝突,則最後的結果是不正確的。 > > 臨界區是指能夠由應用程式的多個執行緒同時執行並公開應用程式存取所使用的任何共享資料或資源的任何程式碼段。 > > 當執行緒在沒有執行緒同步的情況下運行關鍵部分時,會發生競爭條件。執行緒透過臨界區「競賽」來寫入或讀取共享資源,並且根據執行緒完成「競賽」的順序,程式輸出會改變。 > > 在競爭條件下,執行緒存取可能由其他執行緒同時處理的共享資源或程式變量,從而導致應用程式資料不一致 > #### 重要性 * 數據不一致:競爭狀態可能導致數據不一致和不可預測的結果 * 錯誤難以追踪:由於競爭狀態的結果通常依賴於執行緒的具體交錯順序,因此它們可能難以重現和調 ## 如何避免多執行緒問題 ### 如何避免死鎖? - 避免嵌套鎖Avoid Nested Locks:這是死鎖的主要原因。死鎖主要發生在我們給多個執行緒加鎖的時候。如果您已經給一個執行緒提供了鎖,請避免給多個執行緒提供鎖。 - 避免不必要的鎖定Avoid Unnecessary Locks:您應該只鎖定那些需要的成員。擁有不必要的鎖可能會導致死鎖。作為最佳實踐,請盡可能減少鎖定事物的需求。 - 鎖定機制:例如互斥鎖(Mutex)或信號量(semaphore)等 ### 如何避免競爭條件? 競爭條件發生在程式碼的關鍵部分(critical section)。透過使用鎖、原子變數(atomic variables)和訊息傳遞(message passing)等技術,可以透過關鍵部分內的適當執行序同步來避免這些問題。 ## Reference #### [wiki/Race_condition](https://en.wikipedia.org/wiki/Race_condition) #### [2019 。Cameron Wilson。Educative。Multithreading and concurrency fundamentals](https://www.educative.io/blog/multithreading-and-concurrency-fundamentals) #### [2019。Jim Anderson。realpython.com。Speed Up Your Python Program With Concurrency](https://realpython.com/python-concurrency/) 包含系統性的課程介紹與python中的模組使用方法 > - Table of Contents > * What Is Concurrency? > * What Is Parallelism? > * When Is Concurrency Useful? > * How to Speed Up an I/O-Bound Program > * How to Speed Up a CPU-Bound Program > * When to Use Concurrency - 簡體中文。[Robot1024。知乎。通过并发加速你的 python 程序](https://zhuanlan.zhihu.com/p/114329835) - [2019。Jim Anderson。realpython.com。An Intro to Threading in Python](https://realpython.com/intro-to-python-threading/) #### [2023。@combo-tw。Synchronization (資料同步)](https://hackmd.io/@combo-tw/Linux-%E8%AE%80%E6%9B%B8%E6%9C%83/%2F%40combo-tw%2FB16v1IRBB) #### [2023。@RinHizakura。Linux 核心設計: Synchronization](https://hackmd.io/@RinHizakura/rJhEpdyNw#)