iOS GCD中如何控制最大併發數
//聯絡人:石虎
QQ: 1224614774暱稱:嗡嘛呢叭咪哄
一、概述
1、GCD併發的困擾
-
在GCD中有兩種佇列,分別是序列佇列和併發佇列。在序列佇列中,同一時間只有一個任務在執行,不能充分利用多核 CPU 的資源,效率較低。
-
併發佇列可以分配多個執行緒,同時處理不同的任務;效率雖然提升了,但是多執行緒的併發是用時間片輪轉方法實現的,執行緒建立、銷燬、上下文切換等會消耗CPU 資源。
-
目前iPhone的處理器是多核(2個、4個),適當的併發可以提高效率,但是無節制地併發,如將大量任務不加思索就用併發佇列來執行,這隻會大量增加執行緒數,搶佔CPU資源,甚至會擠佔掉主執行緒的 CPU 資源(極端情況)。
-
此外,提交給併發佇列的任務中,有些任務內部會有全域性的鎖(如 CoreText 繪製時的 CGFont 內部鎖),會導致執行緒休眠、阻塞;一旦這類任務多,併發佇列還需要建立新的執行緒來執行其他任務;這種情況下,執行緒數大量增加是避免不了的。
2、優雅的NSOperationQueue
-
NSOperationQueue是iOS提供的工作佇列,開發者只需要將任務封裝在NSOperation的子類(NSBlockOperation、NSInvocationOperation或自定義NSOperation子類)中,然後新增進NSOperationQueue佇列,佇列就會按照優先順序及工作的從屬依賴關係(如果有的話)組織執行。
-
NSOperationQueue中,已經考慮到了最大併發數的問題,並提供了maxConcurrentOperationCount屬性設定最大併發數(該屬性需要在任務新增到佇列中之前進行設定)。maxConcurrentOperationCount預設值是-1;如果值設為0,那麼不會執行任何任務;如果值設為1,那麼該佇列是序列的;如果大於1,那麼是並行的。
NSOperationQueue *queue = [[NSOperationQueue alloc]init];queue.maxConcurrentOperationCount = 2;//新增Operation任務...
-
第三方庫如SDWebImage庫和AFNetworking 中就是採用NSOperationQueue來控制最大併發數的。
說明:NSOperationQueue使用詳見多執行緒程式設計3 - NSOperationQueue 和 NSOperation
3、我們該怎麼辦
-
GCD多執行緒方案很優秀,在iOS 4 與 MacOS X 10.6之後,NSOperationQueue的底層就是用GCD來實現的。
-
NSOperationQueue在控制最大併發數上的確很方便,但是GCD也提供了某些機制可以實現控制最大併發數的效果。
-
開發中NSOperationQueue和GCD都可以用,視場景而定(個人更喜歡用GCD)。
二、QSDispatchQueue方案
1、GCD的訊號量機制(dispatch_semaphore)
-
訊號量是一個整型值,有初始計數值;可以接收通知訊號和等待訊號。當訊號量收到通知訊號時,計數+1;當訊號量收到等待訊號時,計數-1;如果訊號量為0,執行緒會被阻塞,直到訊號量大於0,才會繼續下去。
-
使用訊號量機制可以實現執行緒的同步,也可以控制最大併發數。以下是如何控制最大併發數的程式碼。
dispatch_queue_t workConcurrentQueue = dispatch_queue_create(
"cccccccc", DISPATCH_QUEUE_CONCURRENT);dispatch_queue_t serialQueue
= dispatch_queue_create("sssssssss",DISPATCH_QUEUE_SERIAL);dispatch
_semaphore_t semaphore = dispatch_semaphore_create(3);for (NSInteger
i = 0; i < 10; i++) {dispatch_async(serialQueue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_async(workConcurrentQueue, ^{
NSLog(@"thread-info:%@開始執行任務%d",[NSThread
currentThread],(int)i);sleep(1);
NSLog(@"thread-info:%@結束執行任務%d",[NSThread
currentThread],(int)i);dispatch_semaphore_signal(semaphore);});
});}
NSLog(@"主執行緒...!");
說明:從執行結果中可以看出,雖然將10個任務都非同步加入了併發佇列,但是訊號量機制控制了最大執行緒併發數,始終是3個執行緒在執行任務。此外,這些任務也沒有阻塞主執行緒。
2、QSDispatchQueue方案的實現
1)直接在程式碼中使用GCD的訊號量,不夠優雅,程式碼也很冗餘;基於此,QSDispatchQueue方案出來了。(程式碼很簡單,一共兩個檔案)
2)QSDispatchQueue方法宣告如下:
//[email protected] QSDispatchQueue : NSObject#pragma mark
- main queue + global queue/** 全域性併發佇列的最大併發數,預設4 */+ (QSDispatchQueue *)mainThreadQueue;
+ (QSDispatchQueue *)defaultGlobalQueue;
+ (QSDispatchQueue *)lowGlobalQueue;
+ (QSDispatchQueue *)highGlobalQueue;
+ (QSDispatchQueue *)backGroundGlobalQueue;
#pragma mark [email protected]
(nonatomic,assign,readonly)NSUInteger concurrentCount;- (instancetype)init;
/** 預設最大併發數是1 @param queue 併發佇列 */
- (instancetype)initWithQueue:(dispatch_queue_t)queue;
/** @param queue 併發佇列 @param concurrentCount 最大併發數,應大於1 */
- (instancetype)initWithQueue:(dispatch_queue_t)queue
concurrentCount:(NSUInteger)concurrentCount;//同步-
(void)
sync:(dispatch_block_t)block;//非同步- (void)async:
(dispatch
_block_t)block;@end
3、QSDispatchQueue方案的使用
dispatch_queue_t workConcurrentQueue = dispatch_queue_create(
"cccccccc",
DISPATCH_QUEUE_CONCURRENT);QSDispatchQueue *queue = [[QSDispatchQueue alloc]initWithQueue:
workConcurrentQueue concurrentCount:3];for (NSInteger i = 0; i < 10;
i++) {[queue async:^{
NSLog(@"thread-info:%@開始執行任務%d",
[NSThread currentThread],(int)i);sleep(1);
NSLog(@"thread-info:%@結束執行任務%d",
[NSThread currentThread],(int)i);}];
}NSLog(@"主執行緒任務...");
說明:從執行結果中來看,通過QSDispatchQueue方案也到達了最大執行緒併發數的目的。
-
使用QSDispatchQueue方案,程式碼更簡潔,讓開發者不用去時刻注意訊號量的處理,只關注任務即可。
三、小結
-
在iOS開發中,我們常將耗時任務提交給GCD的併發佇列,但是併發佇列並不會去管理最大併發數,無限制提交任務給併發佇列,會給效能帶來問題。
-
YYKit元件中的YYDispatchQueuePool 也能控制併發佇列的併發數;其思路是為不同優先順序建立和 CPU 數量相同的 serial queue,每次從 pool 中獲取 queue 時,會輪詢返回其中一個 queue。
-
QSDispatchQueue是使用訊號量讓併發佇列中的任務併發數得到抑制;YYDispatchQueuePool是讓一定數量的序列佇列代替併發佇列,避開了併發佇列不好控制併發數的問題。
謝謝!!!
相關推薦
iOS GCD中如何控制最大併發數
//聯絡人:石虎 QQ: 1224614774暱稱:嗡嘛呢叭咪哄 一、概述 1、GCD併發的困擾 在GCD中有兩種佇列,分別是序列佇列和併發佇列。在序列佇列中,同一時間只有一個任務在執行,不能充分利用多核 CPU 的資源,效率較低。 併發佇列可以分配多
2018年最後一天 VsCode中執行nodeJs程式碼的簡單方法 Pgsql和Mysql的對比 Tomcat的最大併發數 Spring AOP不起作用原因
發現2017的隨筆總結依舊適用,想堅持每天寫點東西分享,但感覺每天能原創分享的內容真的不多,尤其是要把自己想分享的內容寫清楚也需要額外花費很多的時間,這讓本來平時就工作比較忙的自己疲於應付,於是乎就轉載自己看到的一些好的文章分享,甚至有些文章自己都沒完全看完就發,湊合著完成了任務,但自己的成就感很低。因此我不
mysql 檢視連線數,狀態,最大併發數
show status like '%max_connections%'; ##mysql最大連線數set global max_connections=1000 ##重新設定show variables like '%max_connections%'; ##查詢資料庫當前設定的最大連線數 show gl
瀏覽器同域名請求的最大併發數限制
當我們在瀏覽網頁的時候,對瀏覽速度有一個重要的影響因素,就是瀏覽器的併發數量。併發數量簡單通俗的講就是,當瀏覽器網頁的時候同時工作的進行數量。 如果同時只有2個併發連線數數量,那網頁開啟的時候只能依賴於
(CSDN遷移) JAVA多執行緒實現-可控最大併發數執行緒池(newFixedThreadPool)
上篇文章中介紹了單執行緒化執行緒池newSingleThreadExecutor,可控最大併發數執行緒池(newFixedThreadPool)與其最大的區別是可以通知執行多個執行緒,可以簡單的將newSingleThreadExecutor理解為newFixedThreadPool(1)。例如執行一下兩個程
Mysql 檢視連線數,狀態 最大併發數
-- show variables like '%max_connections%'; 檢視最大連線數 set global max_connections=1000 重新設定 mysql> show status like 'Threads%'; +---
找陣列中絕對值最大的數,並保留規定的小數點數
#include using namespace std; #include<math.h> #include float date[8] = { -200.1,-40.5,80,99.367,0,-778.354,666,454.235 }; in
Mysql 檢視連線數,狀態 最大併發數 && 怎麼設定才合理
show status like '%max_connections%'; ##mysql最大連線數 set global max_connections=1000 ##重新設定 show variables like '%max_connections%'; ##查詢資料庫當前設定的最大連線數 show
Mysql 檢視連線數,狀態 最大併發數(贊)
1.show status Threads_connected 當前的連線數 Connections 試圖連線到(不管是否成功)MySQL伺服器的連線數。 Max_used_connections 伺服器啟動後已經同時使用的連線的最大數量。 2.set GLOBAL max_con
Tomcat的效能與最大併發數
當一個程序有 500 個執行緒在跑的話,那效能已經是很低很低了。Tomcat 預設配置的最大請求數是 150,也就是說同時支援 150 個併發,當然了,也可以將其改大。當某個應用擁有 250 個以上併發的時候,應考慮應用伺服器的叢集。具體能承載多少併發,需要看硬體的配置,C
使用Filter限制J2EE最大併發數
在開發J2EE的過程往往需要限制併發請求量從而減少伺服器異常的可能性。而這些通常都是通過叢集手段或外部代理來實現的。本文主要介紹單個應用如何不依賴其他程式來解決這個問題。 J2EE的每個請求都是經由過濾器(責任鏈模式),Servlet來執行的,每個請求的進入都需要過濾器的准
oracle 最大併發數 會話數查詢
SQL> select count(*) from v$session #當前的連線數 SQL> Select count(*) from v$session where status='ACTIVE' #併發連線數 SQL> select value
oracle12c 報錯: ora01792 表或檢視中的最大列數為1000
安裝好Oracle12C,使用SQL語句進行查詢時,當查詢的列沒有達到1000,但是關聯的表過多,關聯表的總列數超過了1000的話,會報上面的錯誤。 解決方案如下: 用SysDba登入,執行以下這句話就可解決:alter system set "_fix_co
Apache 設定最大併發數
prefork的工作原理是, 控制程序在最初建立“StartServers”個子程序後,為了滿足MinSpareServers設定的需要建立一個程序,等待一秒鐘,繼續建立兩 個,再等待一秒鐘,繼續建立四個……如此按指數級增加建立的程序數,最多達到每秒32個,直到滿足MinSpareServers設定的值為止
設定springboot自帶tomcat的最大連線數和最大併發數
從原始碼來看,最大連線數和最大併發數預設是10000和200 可以通過工程下的application.yml配置檔案來改變這個值 server: tomcat: uri-enco
Oracle最大併發數&License情況
檢視當前license情況 SQL> show parameter license; NAME TYPE VALUE ----------------------------------
iOS GCD最大併發控制
dispatch_semaphore_t sem = dispatch_semaphore_create(1); dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); 這兩句程式碼為什麼會閃退 最後訊號數量不對等, d
求數組中的最大值並把它放到最後
創建 ++ and ati ofa () out arrays 之間 import java.util.Arrays;import java.util.Random;public class MaxOfArray { public static void main(S
ORA-01795: 列表中的最大表達式數為 1000
條件數 express ora- bsp else number sql語句 截取 lec 系統報出一SQL異常,內容如下: java.sql.SQLException: ORA-01795: maximum number of expressions in a list
51Nod—1174 區間中最大的數 線段樹模版
using ace pan struct 註意 truct logs mark mar 在大佬們題解的幫助下算是看懂了線段樹吧。。。在這mark下防一手轉頭就忘。 #include<iostream> #include<stdio.h> using