日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

NSOperation, NSOperationQueue 原理探析

發(fā)布時(shí)間:2023/11/29 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NSOperation, NSOperationQueue 原理探析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

通過(guò)GNUstep的Foundation來(lái)嘗試探索下NSOperation,NSOperationQueue

?

示例程序

?

寫(xiě)一個(gè)簡(jiǎn)單的程序

?

- (void)viewDidLoad {

????[super viewDidLoad];

????// Do any additional setup after loading the view, typically from a nib.

????

????[self configurationQueue];

????LDNSOperation *operation = [[LDNSOperation alloc] init];

????[self.operationQueue addOperation:operation];

????[NSThread sleepForTimeInterval:3];

????[operation cancel];

????

}

?

-(void)configurationQueue{

????self.operationQueue = [[NSOperationQueue alloc] init];

????self.operationQueue.maxConcurrentOperationCount = 4;

}

?

LDNSOperation為NSOperation的子類(lèi),重寫(xiě)strat方法

?

-(void)start{

????while (true) {

????????if(self.cancelled){

????????????NSLog(@"已經(jīng)取消");

????????????return;

????????}

????????NSLog(@"start");

????????[NSThread sleepForTimeInterval:1];

????}

}

?

實(shí)現(xiàn)的效果很簡(jiǎn)單,打印三個(gè)strat,然后結(jié)束operation。

?

初探

?

根據(jù)閱讀GNU的源碼,也只能是猜想,但是嘗試了很多方法,沒(méi)有找到可以驗(yàn)證的方案,但是實(shí)現(xiàn)原理上還是有很多相似處的。

?

NSOperation有三種狀態(tài),isReady, isExecuting, isFinished.

?

很多其他的參數(shù)也會(huì)隨著NSOperationQueue的addOperation操作而變化著。

?

例如:

?

[self.operationQueue addOperation:operation];

?

添加一個(gè)未完成的NSOperation,其實(shí)就是將NSOperation添加到一個(gè)動(dòng)態(tài)數(shù)組當(dāng)中

?

- (void) addOperation: (NSOperation *)op

{

??if (op == nil || NO == [op isKindOfClass: [NSOperation class]])

????{

??????[NSException raise: NSInvalidArgumentException

??format: @"[%@-%@] object is not an NSOperation",

NSStringFromClass([self class]), NSStringFromSelector(_cmd)];

????}

??[internal->lock lock];

??if (NSNotFound == [internal->operations indexOfObjectIdenticalTo: op]

????&& NO == [op isFinished])

????{

??????[op addObserver: self

?? forKeyPath: @"isReady"

??????options: NSKeyValueObservingOptionNew

??????context: NULL];

??????[self willChangeValueForKey: @"operations"];

??????[self willChangeValueForKey: @"operationCount"];

??????[internal->operations addObject: op];

??????[self didChangeValueForKey: @"operationCount"];

??????[self didChangeValueForKey: @"operations"];

??????if (YES == [op isReady])

??????{

??????????[self observeValueForKeyPath: @"isReady"

??????ofObject: op

change: nil

?????? context: nil];

??????}

????}

??[internal->lock unlock];

}

?

internal就是一個(gè)內(nèi)部類(lèi),指代的就是NSOperationQueue,這里也是一個(gè)KVO的手動(dòng)通知,進(jìn)行operations,與operationCount的改變通知。

?

這里lock是NSRecursiveLock(遞歸鎖),原因我猜測(cè)是因?yàn)檫f歸鎖的特性是可以被同一線程多次請(qǐng)求,而不會(huì)引起死鎖。同一線程的多次addOperation操做情況還是很多的。

?

每一次屬性的變化,都伴隨著其他屬性的改變

?

- (void) observeValueForKeyPath: (NSString *)keyPath

?????? ofObject: (id)object

???????????????????????? change: (NSDictionary *)change

????????????????????????context: (void *)context

{

??[internal->lock lock];

??if (YES == [object isFinished])

????{

??????internal->executing--;

??????[object removeObserver: self

??forKeyPath: @"isFinished"];

??????[internal->lock unlock];

??????[self willChangeValueForKey: @"operations"];

??????[self willChangeValueForKey: @"operationCount"];

??????[internal->lock lock];

??????[internal->operations removeObjectIdenticalTo: object];

??????[internal->lock unlock];

??????[self didChangeValueForKey: @"operationCount"];

??????[self didChangeValueForKey: @"operations"];

????}

??else if (YES == [object isReady])

????{

??????[object removeObserver: self

??forKeyPath: @"isReady"];

??????[internal->waiting addObject: object];

??????[internal->lock unlock];

????}

??[self _execute];

}

?

其實(shí)在maxConcurrentOperationCount和suspended的setter方法里面都會(huì)調(diào)用_execute方法,以及在其他屬性如operationCount、operations、值發(fā)生變化的時(shí)候都會(huì)調(diào)用它。

?

那么_execute究竟是什么?

?

整個(gè)源碼都拿上來(lái)

?

- (void) _execute

{

??NSInteger max;

?

??[internal->lock lock];

?

??max = [self maxConcurrentOperationCount];

??if (NSOperationQueueDefaultMaxConcurrentOperationCount == max)

????{

??????max = maxConcurrent;

????}

?

??while (NO == [self isSuspended]

????&& max > internal->executing

????&& [internal->waiting count] > 0)

????{

??????NSOperation *op;

??????op = [internal->waiting objectAtIndex: 0];

??????[internal->waiting removeObjectAtIndex: 0];

??????[op addObserver: self

?? forKeyPath: @"isFinished"

??????options: NSKeyValueObservingOptionNew

??????context: NULL];

??????internal->executing++;

??????if (YES == [op isConcurrent])

{

??????????[op start];

}

??????else

{

??NSUInteger pending;

?

??[internal->cond lock];

??pending = [internal->starting count];

??[internal->starting addObject: op];

??if (0 == internal->threadCount

????|| (pending > 0 && internal->threadCount

????{

??????internal->threadCount++;

??????[NSThread detachNewThreadSelector: @selector(_thread)

?????? toTarget: self

???? withObject: nil];

????}

??/* Tell the thread pool that there is an operation to start.

?? */

??[internal->cond unlockWithCondition: 1];

}

????}

??[internal->lock unlock];

}

?

從源碼中可以看到,根據(jù)isConcurrent分為直接執(zhí)行,和非直接執(zhí)行,isConcurrent為YES的話(huà)可以直接執(zhí)行start操作,但是如果isConcurrent為NO,那么這里使用detachNewThreadSelector來(lái)創(chuàng)建新的線程去執(zhí)行start。

?

總結(jié)下來(lái):

?

  • 所有的線程都很忙,并且沒(méi)有達(dá)到threadCount的最大值的時(shí)候會(huì)創(chuàng)建新的線程,這代表queue并不是一個(gè)線程,也有可能有幾個(gè)

  • _execute就是一個(gè)執(zhí)行隊(duì)列,依次將等待隊(duì)列里面的所有operation進(jìn)行start。

?

其實(shí)對(duì)于start函數(shù)來(lái)說(shuō)的話(huà),一個(gè)NSOperation并沒(méi)有新創(chuàng)建一條線程,依然操作在[NSThread currentThread]中,感興趣可以去做一下測(cè)試。從源碼中也是可以看出來(lái)的,

?

- (void) start

{

??NSAutoreleasePool *pool = [NSAutoreleasePool new];

??double prio = [NSThread??threadPriority];

?

??[internal->lock lock];

??NS_DURING

????{

??????if (YES == [self isConcurrent])

{

??[NSException raise: NSInvalidArgumentException

??????format: @"[%@-%@] called on concurrent operation",

????NSStringFromClass([self class]), NSStringFromSelector(_cmd)];

}

??????if (YES == [self isExecuting])

{

??[NSException raise: NSInvalidArgumentException

??????format: @"[%@-%@] called on executing operation",

????NSStringFromClass([self class]), NSStringFromSelector(_cmd)];

}

??????if (YES == [self isFinished])

{

??[NSException raise: NSInvalidArgumentException

??????format: @"[%@-%@] called on finished operation",

????NSStringFromClass([self class]), NSStringFromSelector(_cmd)];

}

??????if (NO == [self isReady])

{

??[NSException raise: NSInvalidArgumentException

??????format: @"[%@-%@] called on operation which is not ready",

????NSStringFromClass([self class]), NSStringFromSelector(_cmd)];

}

??????if (NO == internal->executing)

{

??[self willChangeValueForKey: @"isExecuting"];

??internal->executing = YES;

??[self didChangeValueForKey: @"isExecuting"];

}

????}

??NS_HANDLER

????{

??????[internal->lock unlock];

??????[localException raise];

????}

??NS_ENDHANDLER

??[internal->lock unlock];

?

??NS_DURING

????{

??????if (NO == [self isCancelled])

{

??[NSThread setThreadPriority: internal->threadPriority];

??[self main];

}

????}

??NS_HANDLER

????{

??????[NSThread setThreadPriority:??prio];

??????[localException raise];

????}

??NS_ENDHANDLER;

?

??[self _finish];

??[pool release];

}

?

總結(jié)

?

整個(gè)過(guò)程伴隨著很多屬性的變化,同步這些屬性,KVO在其中起著舉足輕重的作用,通過(guò)源碼也可以發(fā)現(xiàn),NSOperationQueue對(duì)NSOperation的處理分為并發(fā)和非并發(fā)的情況。如果不想采用非并發(fā)的形式,我們可以直接自定義子類(lèi)化,在NSOperationQueue中添加,并且管理就可以了,功能類(lèi)似線程池的用法。

?

但是如果想要自定義的NSOperation是并發(fā)的僅僅是重寫(xiě)isExecuting、isFinished、isConcurrent、isAsynchronous 這四個(gè)方法,isAsynchronous反回YES就可以了嗎?

?

從源碼中我們可以看到,NSOperation的start依然使用的[NSThread currentThread]。所以依然需要自己創(chuàng)建,例如:

?

[NSThread detachNewThreadSelector:@selector(start) toTarget:self withObject:nil];

?

現(xiàn)在來(lái)思考下,也就明白了為什么NSOperationQueue要有兩種處理方式了,如果NSOperation支持并發(fā),然后NSOperationQueue在為其分配線程,那就是線程里面又跑了一條線程,這樣就很尷尬了,通過(guò)isConcurrent可以避免這種現(xiàn)象。

?

通常在大多數(shù)時(shí)候我們并不會(huì)直接去使用自定義的 NSOperation ,如果操作不復(fù)雜,可以直接使用 NSInvocationOperation 和 NSBlockOperation 這兩個(gè)子類(lèi)。

?

如果真的需要使用多線程,通常都會(huì)用 NSOperationQueue來(lái)處理就可以了。

?

這里也是僅僅簡(jiǎn)單的探索了一下,上面的源碼是封裝的NSThread,但是Apple的實(shí)現(xiàn)可能封裝的不是NSThread,因?yàn)閿帱c(diǎn)后并沒(méi)有看到跟NSThread相關(guān)的東西,還是有很多細(xì)節(jié)需要去推敲。

?

?

轉(zhuǎn)載于:https://www.cnblogs.com/fengmin/p/6108165.html

總結(jié)

以上是生活随笔為你收集整理的NSOperation, NSOperationQueue 原理探析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。