Threading: what are the advantages and disadvantages of using thread pools? 9934033 吳怡萱 9934034 鍾少軒 9934042 鄭景文 1/21
Outline Thread Pools What is thread? What is thread Pools? Case Analysis What language use thread pool? How to use thread pool? Comparison Create-as-need Destroy-when-done Conclusion What do we learn from thread pools? 2/21
Outline Thread Pools What is thread? What is thread Pools? Case Analysis What language use thread pool? How to use thread pool? Comparison Create-as-need Destroy-when-done Conclusion What do we learn from thread pools? 3/21
What is thread ? 執行程式的最小單位 一個process可產生且並行多個thread 4/21 在介紹Thread之前,我們必須先把Program和Process這兩個觀念作一個釐清。 Program:一群程式碼的集合,用以解決特定的問題。以物件導向的觀念來類比,相當於Class。 Process:由Program所產生的執行個體,一個Program可以同時執行多次,產生多個Process。以物件導向的觀念來類比,相當於Object。每一個Process又由以下兩個東西組成 一個Memory Space。相當於Object的variable,不同Process的Memory Space也不同,彼此看不到對方的Memory Space。 一個以上的Thread。Thread代表從某個起始點開始(例如main),到目前為止所有函數的呼叫路徑,以及這些呼叫路徑上所用到的區域變數。當然程式的執行狀態,除了紀錄在主記憶體外,CPU內部的暫存器(如Program Counter, Stack Pointer, Program Status Word等)也需要一起紀錄。所以Thread又由下面兩項組成 Stack:紀錄函數呼叫路徑,以及這些函數所用到的區域變數 目前CPU的狀態 由上面的描述中,我們在歸納Thread的重點如下 一個Process可以有多個Thread。 同一個Process內的Thread使用相同的Memory Space,但這些Thread各自擁有其Stack。換句話說,Thread能透過reference存取到相同的Object,但是local variable卻是各自獨立的。 作業系統會根據Thread的優先權以及已經用掉的CPU時間,在不同的Thread作切換,以讓各個Thread都有機會執行。 4/21
Issues about create or destroy threads: Destroy 太多導致可能又需另外花時間create Create 速度太慢讓等待時間太久 Destroy 速度太慢,占用資源太久造成其他processes挨餓 The algorithm used to determine when to create or destroy threads will have an impact on the overall performance: 1.create too many threads, and resources are wasted and time also wasted creating any unused threads 2.destroy too many threads and more time will be spent later creating them again 3.creating threads too slowly might result in poor client performance (long wait times) 4.destroying threads too slowly may starve other processes of resources 5/21
What is thread pool? 預先產生出一定數量的thread,使其保持在ready的狀態,等待需要執 行的processes 6/21
I have to wait for a girl…… 7/21
OK! Let’s go~ 8/21
Implementation 需要一個可以製造thread並將其保持在理想狀態的方法 需要container來儲存已產生的thread 建立標準介面或是class,讓在thread pool中的thread可以被使用 [Implementation]: 隨環境不同而有不同,簡單來說需要以下幾項: 1.A way to create threads and hold them in an idle state. This can be accomplished by having each thread wait at a barrier until the pool hands it work. (This could be done with mutexes as well.) 2.A container to store the created threads, 像是queue或是任何其他的資料結構可以加入 thread在pool中 and pull one out. 3.A standard interface or abstract class for the threads to use in doing work. This might be an abstract class called Task with an execute() method that does the work and then returns 9/21
Outline Thread Pools What is thread? What is thread Pools? Case Analysis What language use thread pool? How to use thread pool? Comparison Create-as-need Destroy-when-done Conclusion What do we learn from thread pools? 10/21
Thread Pools – 以C語言實作 紀錄要執行的function pointer與要傳遞的參數 存放所有的 Thread 與 Job Queue typedef struct { void (*function)(void *); void *argument; } threadpool_task_t; struct threadpool_t { pthread_mutex_t lock; pthread_cond_t notify; pthread_t *threads; threadpool_task_t *queue; int thread_count; int queue_size; int head; int tail; int count; int shutdown; int started; }; 首先 Thread Pool 要有的東西就是 job 或者是 task 讓 Thread 知道他們要做什麼事情。 所以只要有一個資料結構紀錄要執行的 function pointer 與要傳遞的參數即可。 接下來就是 Thread Pool 本身,他必須存放所有的 Thread 與 Job Queue 這邊他使用了一個 pthread_t 的 pointer 來紀錄所有的 Thread,簡單來說就是一個 pthread_t 的 array,而 head, tail 就是紀錄 array 的 offset。 threadpool_task_t 也是一樣的原理,真是出乎意料的簡單。 11/21
使用一個 pthread array 與一個 job array 存放所有的 thread 與 jobs。 pool->threads = (pthread_t *) malloc(sizeof(pthread_t) * thread_count); pool->queue = (threadpool_task_t *) malloc(sizeof(threadpool_task_t) * queue_size); 使用一個 pthread array 與一個 job array 存放所有的 thread 與 jobs。 因此需要在一開始的時候就決定 Thread Pool 與 Jobs 的最大數量。 12/21
13/21 在for(;;)裡 Thread先搶奪pool的lock, 搶到之後若發現無工作執行, static void *threadpool_thread(void *threadpool) { threadpool_t *pool = (threadpool_t *)threadpool; threadpool_task_t task; for(;;) { pthread_mutex_lock(&(pool->lock)); while((pool->count == 0) && (!pool->shutdown)) { pthread_cond_wait(&(pool->notify), &(pool->lock)); } if((pool->shutdown == immediate_shutdown) || ((pool->shutdown == graceful_shutdown) && (pool->count == 0))) { break; task.function = pool->queue[pool->head].function; task.argument = pool->queue[pool->head].argument; pool->head += 1; pool->head = (pool->head == pool->queue_size) ? 0 : pool->head; pool->count -= 1; pthread_mutex_unlock(&(pool->lock)); (*(task.function))(task.argument); pool->started--; pthread_exit(NULL); return(NULL); 在for(;;)裡 Thread先搶奪pool的lock, 搶到之後若發現無工作執行, 會執行pthread cond wait來等待通知 Pool->lock也會被unlock 在沒有工作的情形下所有thread會等待。 但當thread被pthread cond signal喚醒時, Thread會從新取得Pool->lock, 此時取出queue中的task, 取出完畢後其他喚醒thread亦可取得task 在 for(;;) 裡面,Thread 第一件要做的事情就是去搶奪 pool 的 lock,當搶到 lock 的 Thread 發現沒有工作可以做的時候, 就會執行 pthread_cond_wait 來等待通知。這時候 pool->lock 會被 Unlock,因此這時候其他 Thread 也可以進來這個區域。 所以在完全沒有工作的情況下,所有的 Thread 都會在這邊 Waiting。 當 Thread 被透過 pthread_cond_signal 喚醒的時候,該 Thread 就會重新取得 pool->lock。 這時他就可以安心的取出 queue 中的 task,等待取出完畢之後,再 unlock 讓其他被喚醒的 Thread 也可以去取得 Task。 之後就是執行 task 中的 function pointer 做該做的工作。 13/21
Thread Pools – 以Java實作 以往用 Java 寫 Thread Pool 並不是簡單的事, 不過在 JavaSE 5.0 後,很簡單就可以做出 Thread Pool 的效果。 Thread Pool 的 Thread 生命週期、request queue、分發request 等細節Java都已經 寫好了,因此要實作一個thread pool所要做的就只 有設定 Thread 的數量和專注在工作的內容。 import java.util.concurrent.Executor; import java.util.concurrent.Executors; 14/21
Executors 也提供了其他的 method 來產生不同的 Thread Pool,如: newSingleThreadExecutor() newCachedThreadPool() newScheduledThreadPool() newSingleThreadScheduledExecutor() 15/21
Outline Thread Pools Case Analysis What language use thread pool? What is thread? What is thread Pools? Case Analysis What language use thread pool? How to use thread pool? Comparison Prons and Cons of Thread Pool Conclusion What do we learn from thread pools? 16/21
Comparison If we need to perform lots of small, simple tasks Thread: create和destroy thread除了需要大量的時間,也會使CPU的負荷大增 Thread Pool: 可以直接從thread pool裡挑一個閒置的thread,能夠大幅減少create和destroy的時間 17/21
創造Thread pool時,OS會評估此程式所需要的thread的最大數量,來決定需要多少個thread待命,資源得以進行較有效的分配 只要創建一個thread pool就可以開始執行task,其餘之task可以在queue裡等待 thread pool裡閒置的thread,不需要產生一堆thread去對應所有的task 雖然小的task適合使用thread pool來實作,但是對於太小的task就變得不太適合, context switch會導致所等待的時間更長 1.This prevents having to incur the overhead of creating a thread a large number of times. 2.Tasks should be small, but not too small, otherwise performance overheads will dominate. 3.Tasks should avoid blocking (waiting idly for other events, including inbound messages or contested locks), otherwise the pool won't consistently utilize the hardware well -- and, in the extreme worst case, the pool could even deadlock. 18/21
由於使用thread pool時,不能給予priority,當要按照priority執行task的時候,不適合使 因為thread pool裡有固定的thread數量,所以若有task長期block,就會影響到其他task 由thread pool所產生的thread皆為background thread,若想要使用foreground thread,就必須直接create一個專屬的thread 19/21
Outline Thread Pools Case Analysis What language use thread pool? What is thread? What is thread Pools? Case Analysis What language use thread pool? How to use thread pool? Comparison Prons and Cons of Thread Pool Conclusion What do we learn from thread pools? 20/21
Pros Cons Conclusion 21/21 減少 create thread的時間 有效進行資源的分配 可以利用較少量的thread完成較大量的task Pros 無法對task 進行priority的排程 Thread pool 所產生的thread皆為background thread 若有task 長時間的block, 其他的task取得thread時間會受影響 Cons 21/21