GCD會建立多少個執行緒
如果為overcommit佇列,有新任務就會重新開闢新的執行緒,其中 dq->dq_width = UINT32_MAX;表示這些佇列不限制併發數。
任何自己建立的佇列預設都依附於系統的DEFAULT佇列,序列的依附於DISPATCH_ROOT_QUEUE_IDX_DEFAULT_OVERCOMMIT_PRIORITY;並行佇列依附於DISPATCH_ROOT_QUEUE_IDX_DEFAULT_PRIORITY
當然也可以自己再重新設定所依附的佇列。
GCD號稱非常高效,底層用的執行緒池,就會想系統怎麼排程才能更好效,執行緒池會建立多少個執行緒:系統如果建立非常多執行緒,那佇列的意義就沒有了,來個任務就建立執行緒,就不用排隊了,並且如果執行緒過多肯定會伴隨著效能下降。那就測試一下系統到底會建立多少個執行緒
### 一、分別建立10個,100個和10000個並行任務
NSInteger taskCount = 10/10000/100;
for (int i = 0; i < taskCount; i++) {
dispatch_async(self.queue, ^{
NSLog(@"thread: @", [NSThread currentThread]);
});
}
最終通過log看taskCount為10時,執行緒個數大約是八九個,看情況不定;taskCount為100和10000時執行緒num是從3到66,總共64個,64是2的6次方,也比較符合程式的一貫風格;因為任務比較輕,所以當任務比較少時到後面分配任務時前面的任務已經做完,所以會在原來的執行緒上執行任務;一旦任務比較多時,就會全力分配執行緒。
### 二、兩個並行佇列各分配10000個任務
結果依然是64,因為都是依附於DISPATCH_ROOT_QUEUE_IDX_DEFAULT_PRIORITY,DISPATCH_ROOT_QUEUE_IDX_DEFAULT_PRIORITY預設為64,不管他那幾個依附於DISPATCH_ROOT_QUEUE_IDX_DEFAULT_PRIORITY,結果都一樣
### 三、並行佇列設定不同優先順序:
for (int i = 0; i < taskCount; i++) {
dispatch_async(self.queue, ^{
NSLog(@"thread: @", [NSThread currentThread]);
});
}
for (int i = 0; i < taskCount; i++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSLog(@"DISPATCH_QUEUE_PRIORITY_HIGH thread: @", [NSThread currentThread]);
});
}
經過測試發現先輸出的是DISPATCH_QUEUE_PRIORITY_DEFAULT(self.queue)的部分然後就開始輸出DISPATCH_QUEUE_PRIORITY_HIGH部分,DISPATCH_QUEUE_PRIORITY_HIGH全部輸出完了後才繼續輸出DISPATCH_QUEUE_PRIORITY_DEFAULT(self.queue);執行緒個數依然為64。
先輸出了DISPATCH_QUEUE_PRIORITY_DEFAULT(self.queue)部分是因為在傳送DISPATCH_QUEUE_PRIORITY_DEFAULT(self.queue)全部任務期間還沒有輪到DISPATCH_QUEUE_PRIORITY_HIGH建立任務,一旦等有了DISPATCH_QUEUE_PRIORITY_HIGH任務就立即執行高優先順序的任務了。
### 四、新增序列佇列:
for (int i = 0; i < taskCount; i++) {
dispatch_async(self.serialQueue, ^{
NSLog(@"serialQueue thread: @", [NSThread currentThread]);
});
}
NSInteger taskCount = 10000;
for (int i = 0; i < taskCount; i++) {
dispatch_async(self.queue, ^{
NSLog(@"thread: @", [NSThread currentThread]);
});
}
執行緒個數為65個,說明當序列佇列加入時肯定會建立一個執行緒對應;同時建立兩個序列佇列然後就會輸出66個執行緒
### 五、序列佇列重新設定依附於一個非overcommit全域性佇列
dispatch_set_target_queue(self.serialQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0));
dispatch_set_target_queue(self.serialQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
執行緒個數為64但是發現無論依附的是高優先順序還是低優先順序,序列佇列都會從開始分配任務就執行;說明當序列佇列和並行佇列依附於同一並行佇列時,序列佇列的優先順序總是高於並行
### 六、序列佇列獲取全域性佇列時flag處設定為1
不管是蘋果官方文件,還是其他人部落格都會說flag處保留欄位暫時都為0,看到過一段gcd原始碼
dispatch_queue_t
dispatch_get_global_queue(long priority, unsigned long flags)
{
if (flags & ~DISPATCH_QUEUE_OVERCOMMIT) {
return NULL;
}
return _dispatch_get_root_queue(priority,
flags & DISPATCH_QUEUE_OVERCOMMIT);
}
從這段原始碼中flags設定為1獲取到的應該是overcommit的佇列,那如果序列佇列依附於overcommit的,那執行緒個數應該是65了;
經測試果然為65,說明flags功能就是來區分獲取的是overcommit還是非overcommit佇列的,只是蘋果暫時不想讓呼叫罷了
### 七、那如果把一個並行佇列依附於一個overcommit佇列,是不是可以建立無數個執行緒?想想就很激動
測試結果為64個,看來蘋果對依附於'overcommit佇列'的並行佇列還是有限制的,依然限制為64個執行緒。
### 八、那我如果兩個並行佇列依附於兩個優先順序的overcommit佇列會出現什麼呢?
dispatch_set_target_queue(self.queue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, -1));
dispatch_set_target_queue(self.queue2, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, -1));
for (int i = 0; i < taskCount; i++) {
dispatch_async(self.queue, ^{
self.count++;
NSLog(@"thread :%@ count %ld", [NSThread currentThread] ,self.count);
});
}
for (int i = 0; i < taskCount; i++) {
dispatch_async(self.queue2, ^{
self.count++;
NSLog(@"queue2 thread :%@ count %ld", [NSThread currentThread] ,self.count);
});
}
經測試,系統並沒有建立128個執行緒,而依然是64個,並且並不是優先輸出依附於高優先順序的並行佇列,而是各個佇列的輸出了4000多個輪流幾次輸出完畢。(他那兩個預設優先順序佇列也是輪流4000多)
說明當並行佇列依附於overcommit佇列時系統會轉交給DEFAULT優先順序的非overcommit佇列。
### 九、兩個同級別並行佇列會怎麼分配執行緒
int sleepTime = 0/1000/10000/100000;
for (int i = 0; i < taskCount; i++) {
dispatch_async(self.queue, ^{
self.count++;
usleep(sleepTime);
NSLog(@"thread :%@ count %ld", [NSThread currentThread] ,self.count);
});
}
for (int i = 0; i < taskCount; i++) {
dispatch_async(self.queue2, ^{
self.count++;
usleep(sleepTime);
NSLog(@"queue2 thread :%@ count %ld", [NSThread currentThread] ,self.count);
});
}
無認是否sleep(),以及休眠的時間是多少都是會先執行self.queuer 4000多個任務,再執行self.queue2的4000多個任務,以次輪換。說明對於對於依附於同一佇列的不同佇列,也會有類似系統對執行緒排程,分配時間片一樣來排程,只是所依據的不再是時間,而是任務個數
### 總結
1.gcd執行緒池,系統會建立64個執行緒給dispatch_get_global_queue獲取的4個並行佇列,當各優先順序都有任務時優先保證高優先順序的;如果序列佇列依附的是系統的並行佇列,則優先順序最高。
2.如果自己再建立序列佇列,系統會在64個執行緒基礎上再建立執行緒給序列佇列。
3.dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,1)
flags處開參傳入非0會獲取到overcommit佇列
4.如果設定並行佇列依附於overcommit佇列,系統會轉交給DISPATCH_QUEUE_PRIORITY_DEFAULT
5.對於依附於同一佇列的不同佇列,也會有類似系統對執行緒排程,分配時間片一樣來排程,只是所依據的不再是時間,而是任務個數 。不以時間而以任務個數肯定也是為了提高效率
系統為序列佇列單獨建立執行緒應該是考慮到:
1.序列佇列如果不單獨建立,很容易被執行更早的並行列隊搶佔完執行緒,導致並行佇列只能等待。
2.就算是搶到一個執行緒,執行完一個任務,下一個任務也不一定能搶到,這樣序列佇列就直接成悲劇了,只能執行一個任務,等一會,再執行一個。
###其他
1.以後有時間再測試建立10000個序列佇列,看系統會建立幾個執行緒,上限會是多少
2.到底為4000多多個少,這個需要再查原始碼了。