本文首發於 個人我的博客html
維基百科中,這麼描述 生產者消費者問題git
生產者消費者問題(英語:Producer-consumer problem),也稱有限緩衝問題(英語:Bounded-buffer problem),是一個多進程同步問題的經典案例。該問題描述了共享固定大小緩衝區的兩個進程——即所謂的「生產者」和「消費者」——在實際運行時會發生的問題。生產者的主要做用是生成必定量的數據放到緩衝區中,而後重複此過程。與此同時,消費者也在緩衝區消耗這些數據。該問題的關鍵就是要保證生產者不會在緩衝區滿時加入數據,消費者也不會在緩衝區中空時消耗數據。github
要解決該問題,就必須讓生產者在緩衝區滿時休眠(要麼乾脆就放棄數據),等到下次消費者消耗緩衝區中的數據的時候,生產者才能被喚醒,開始往緩衝區添加數據。一樣,也可讓消費者在緩衝區空時進入休眠,等到生產者往緩衝區添加數據以後,再喚醒消費者。一般採用進程間通訊的方法解決該問題,經常使用的方法有信號燈法[1]等。若是解決方法不夠完善,則容易出現死鎖的狀況。出現死鎖時,兩個線程都會陷入休眠,等待對方喚醒本身。該問題也能被推廣到多個生產者和消費者的情形。數據庫
咱們公司本身項目中,有個場景,就是IM消息,當咱們收到消息時候,進行一些業務邏輯的處理,還有數據庫的操做,而後刷新列表。存在的問題是,若是消息接收的特別快,例如離線消息,可能登錄的是,有幾百條消息拉取下來,若是每一條每一條的處理,將會致使兩個問題:bash
上述問題,使用生產者-消費者就能解決這個問題dom
爲了簡單高效。咱們用計時器,間隔0.1秒接收一條消息,刷新列表,假設須要2秒。async
@property (nonatomic,strong) NSMutableArray *array;//存放數據
@property (nonatomic,strong) dispatch_semaphore_t semaphore;
複製代碼
NSTimer *curTimer =[NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(producerFuncWithNumber:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:curTimer forMode:NSDefaultRunLoopMode];
[curTimer fire];
複製代碼
//生產者
- (void)producerFuncWithNumber:(NSInteger )number{
number = random()%10;
//生產者生成數據
dispatch_queue_t t = dispatch_queue_create("222222", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(t, ^{
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
[self.array addObject:[NSString stringWithFormat:@"%ld",(long)number]];
NSLog(@"生產了%lu 個",(unsigned long)self.array.count);
dispatch_semaphore_signal(self.semaphore);
});
}
複製代碼
//消費者
- (void)consumerFunc{
dispatch_queue_t t1 = dispatch_queue_create("11111", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(t1, ^{
while (YES) {
if (self.array.count > 0) {
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"消費了%lu 個",(unsigned long)self.array.count);
[self.array removeAllObjects];
[self reload];
dispatch_semaphore_signal(self.semaphore);
}
}
});
}
複製代碼
-(void)reload{
NSLog(@"休眠2秒");
sleep(2);
}
複製代碼
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,strong) NSMutableArray *array;//存放數據
@property (nonatomic,strong) dispatch_semaphore_t semaphore;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//開啓計時器
NSTimer *curTimer =[NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(producerFuncWithNumber:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:curTimer forMode:NSDefaultRunLoopMode];
[curTimer fire];
[self consumerFunc];
}
-(void)reload{
NSLog(@"休眠2秒");
sleep(2);
}
- (NSMutableArray *)array{
if (!_array) {
_array = [NSMutableArray array];
}
return _array;
}
- (dispatch_semaphore_t)semaphore{
if (!_semaphore) {
_semaphore = dispatch_semaphore_create(1);
}
return _semaphore;
}
//生產者
- (void)producerFuncWithNumber:(NSInteger )number{
number = random()%10;
//生產者生成數據
dispatch_queue_t t = dispatch_queue_create("222222", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(t, ^{
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
[self.array addObject:[NSString stringWithFormat:@"%ld",(long)number]];
NSLog(@"生產了%lu 個",(unsigned long)self.array.count);
dispatch_semaphore_signal(self.semaphore);
});
}
//消費者
- (void)consumerFunc{
dispatch_queue_t t1 = dispatch_queue_create("11111", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(t1, ^{
while (YES) {
if (self.array.count > 0) {
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"消費了%lu 個",(unsigned long)self.array.count);
[self.array removeAllObjects];
[self reload];
dispatch_semaphore_signal(self.semaphore);
}
}
});
}
@end
複製代碼
iOS-生產者消費者[5508:75404] 生產了1 個
iOS-生產者消費者[5508:75407] 生產了2 個
iOS-生產者消費者[5508:75406] 生產了3 個
iOS-生產者消費者[5508:75411] 生產了4 個
iOS-生產者消費者[5508:75440] 生產了5 個
iOS-生產者消費者[5508:75443] 生產了6 個
iOS-生產者消費者[5508:75450] 生產了7 個
iOS-生產者消費者[5508:75458] 生產了8 個
iOS-生產者消費者[5508:75463] 生產了9 個
iOS-生產者消費者[5508:75472] 生產了10 個
iOS-生產者消費者[5508:75480] 生產了11 個
iOS-生產者消費者[5508:75481] 生產了12 個
iOS-生產者消費者[5508:75482] 生產了13 個
iOS-生產者消費者[5508:75494] 生產了14 個
iOS-生產者消費者[5508:75518] 生產了15 個
iOS-生產者消費者[5508:75521] 生產了16 個
iOS-生產者消費者[5508:75526] 生產了17 個
iOS-生產者消費者[5508:75528] 生產了18 個
iOS-生產者消費者[5508:75531] 生產了19 個
iOS-生產者消費者[5508:75545] 生產了20 個
iOS-生產者消費者[5508:75405] 消費了20 個
iOS-生產者消費者[5508:75405] 休眠2秒
iOS-生產者消費者[5508:75545] 生產了1 個
iOS-生產者消費者[5508:75531] 生產了2 個
iOS-生產者消費者[5508:75528] 生產了3 個
iOS-生產者消費者[5508:75526] 生產了4 個
iOS-生產者消費者[5508:75521] 生產了5 個
iOS-生產者消費者[5508:75518] 生產了6 個
iOS-生產者消費者[5508:75494] 生產了7 個
iOS-生產者消費者[5508:75482] 生產了8 個
iOS-生產者消費者[5508:75481] 生產了9 個
iOS-生產者消費者[5508:75480] 生產了10 個
iOS-生產者消費者[5508:75472] 生產了11 個
iOS-生產者消費者[5508:75463] 生產了12 個
iOS-生產者消費者[5508:75458] 生產了13 個
iOS-生產者消費者[5508:75450] 生產了14 個
iOS-生產者消費者[5508:75443] 生產了15 個
iOS-生產者消費者[5508:75440] 生產了16 個
iOS-生產者消費者[5508:75406] 生產了17 個
iOS-生產者消費者[5508:75407] 生產了18 個
iOS-生產者消費者[5508:75404] 生產了19 個
iOS-生產者消費者[5508:75411] 生產了20 個
iOS-生產者消費者[5508:75405] 消費了20 個
iOS-生產者消費者[5508:75405] 休眠2秒
iOS-生產者消費者[5508:75411] 生產了1 個
iOS-生產者消費者[5508:75404] 生產了2 個
。。。
複製代碼
由輸出結果可知,每次完成業務邏輯須要2秒的話,能夠等待上次完成,再進行下次取數據,此時,已經有了20條數據,能夠一次性處理,對性能是個挺大的提高。oop
生產者和消費者各自在信號量處理,爲了保證數據的惟一性,須要用信號量 dispatch_semaphore_t semaphore
來保證多條線程不擁擠,不搶數據。性能
以上就是對生產者消費者的簡單實用,實際使用的時候,能夠靈活實用,有時候能有挺大的優化空間。優化