IOS併發編程筆記

1.傳統的併發編輯模型是線程,但線程模型可擴展性依賴程序員經驗(要用多少個線程及如何調度它們),且編寫正確的代碼困難,因此mac和ios採用“異步設計方式”來解決併發問題,異步設計方式是指提供簡單的方式讓用戶可異步執行代碼,只需要提供異步執行的代碼塊,由系統自動幫助創建管理和啓動線程,引入的異步技術有兩個:
1)GCD:將執行任務的代碼塊創建好,添加到dispatch queue,GCD會幫你創建線程並調度任務,系統提供線程管理,比應用實現更高效;線程順序嚴格FIFO;
2)Operation Queue:Objective-C對象,類似於dispatch queue,特點在於可動態調配任務的執行順序,配置任務間的依賴關係,比如a任務可在b任務執行後再執行;同時其是oc的接口,gcd是c的函數接口;
2.dispatch queue分爲serial dispatch queue(也稱爲private dispatch queue)和concurrent dispatch queue(也稱爲global dispatch queue),前者串行,後者併發;同時還有全局的串行queue——main dispatch queue,這是主線程所在的queue,它與應用的run loop交叉運行;
3.通過確保主線程自由響應用戶事件,併發可以很好地提升用戶的響應性。將工作分配 到多核還能提升應用處理的性能,但併發也帶來一定額外開銷,並使代碼更復雜,因此設計階段就要考慮用發,設計出任務及其對應所需要的數據結構;
4.Operation object是NSOperation類的實例,封裝了需要執行的任務和對應的數據,NSOperation本身是基類,必須實現其子類,系統有兩個可現成使用的子類:NSInvocationOperation和NSBlockOperation,前者由一個實例和其方法來進行封裝,適用於有現成方法的情況下使用,類似於target:action;後者則無現有方法情況下,使用塊來進行封裝;operation objects都支持關鍵的特性:
1)允許設置任務間的依賴;
2)支持可選的completion block,在任務完成後調用;
3)支持應用KVO通知來監控operation執行狀態;
4)支持operation優先級設置,影響相對的執行順序;

5)支持取消,中止正在執行的任務;

6)NSOperation對象可重用;

5.operation有兩種執行方法,一是添加到operation queue,另一種是手動調用其start方法,前者不需要處理併發情況,系統會自動創建線程,實現併發;後者默認是同步執行,即是在調用start方法的線程中執行,因此若想併發執行則需要自己手動創建線程,再調用start才能保證併發;
6.創建NSInvocationOperation:
NSInvocationOperation* theOp = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(myTaskMethod:) object:data] autorelease];
7.NSBlockOperation可封裝一個或多個Block,一般先創建時添加一個,後續再根據需要添加多個,調用方法addExecutionBlock:,operation對象執行時,會默認提交所有block到默認優先級的併發dispatch queue,全部block執行完纔算operation完,因此可用BlockOperation來跟蹤一組執行中的block;有點類似於線程的join,如果需要使block串行執行,則需要手動將operation提交到對應的dispatch queue。
8. NSBlockOperation創建示例:NSBlockOperation* theOp = [NSBlockOperation blockOperationWithBlock: ^{ NSLog(@"Beginning operation.\n");
}];
9.定義自定義非併發operation只需要執行主任務,並正確地響應取消事件,NSOperation處理了其它所有事情。對於併發operation, 你必須替換某些現有的基礎設施代碼。
10.每個operation對象至少需要實現以下方法:
1)initialization方法:初始化,將operation對象設置爲已知狀態;
2)自定義main方法:執行任務的內容;
3)判斷取消事件是通過調用isCancelled方法來實現的,可以在任務循環裏一直調用該方法,因爲它的開銷並不大;
11.手動start方式執行operation時,如果想使之併發執行,則有幾個方法需要特殊處理:
1)實現start方法,在其中實現併發,創建線程並執行之;
2)main方法實現可選;
3)isExecuting和isFinished必須實現,用來向外部報告當前任務是否已經在執行或已完成,這兩個方法必須保證可在其它多個線程中同時調用,狀態變化時也需要發了對應的KVO通知;
4)isConcurrent必須實現,用來標記當前的operation是否併發的operation;
5)你如果想單獨處理依賴,還可以實現isReady方法,強制返回NO,直至我們想要的條件成立再返回YES等等;
12.使用NSOperation的addDependency:方法在兩個operation對象之間建立依賴關係;依賴關係不侷限於同一個queue中的operation,但是不能創建循環依賴,否則所有影響到的operations都將無法執行;配置依賴關係必須在operation添加到queue之前,之後添加的依賴關係可能不起作用;
13.setQueuePriority可以設置operation在queue裏的優先級,不同的queue中的operation互不影響,依賴關係需要在優先級之前先滿足;通過setThreadPriority方法可設置底層線程的優先級,該優先級只有main方法範圍內有效,之前與之後的代碼仍是默認優先級;
14.內存管理方面:operation對象需要用autoreleasepool包起來;避免Per-Thread storage來存儲數據,即不要關聯任何數據到非自己創建的線程上,系統管理的線程其週期不明確;自己需要處理operation start之後的所有異常與錯誤;
15.將operation加到queue中:
NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];
[aQueue addOperation:anOp]; // Add a single operation
[aQueue addOperations:anArrayOfOps waitUntilFinished:NO]; // Add multiple operations
[aQueue addOperationWithBlock:^{ /* Do something. */
}];
16.setMaxConcurrentOperationCount: 方法可以配置operation queue的最大併發操作數量。設爲1就表示 queue每次只能執行一個操作。不過operation 執行的順序仍然依賴於其它因素,像操作是否準備好和優先級等。因此串行化的operation queue並不等同於 GCD中的串行dispatch queue。
17.只有你確定不再需要Operations對象時,才應該取消它。發出取消命令會將Operations對象設置爲"Canceled"狀態,會阻止它被執行。由於取消也被認爲是完成,依賴於它的其它Operations對象會收到適當的KVO通知,並清除依賴狀態,然後得到執行。
18.如果想臨時掛起operations的執行,可以掛起對應的queue,調用方法setSuspended,掛起queue時不會導致正在執行的operation中途暫停,只會簡單阻止調度新的operation執行。
19.dispatch queue的幾個關鍵點:
1)dispatch queue之間中併發執行的,要串行只能在同一個queue中實現;
2)100個不同的queues啓動100個任務,並不代表100個任務都在同時執行,具體取決於系統的核數;
3)系統在選擇執行哪個任務時,會考慮queue的優先級;
4)queue中的任務是任何時候都準備好運行的,不像operation一樣有isReady接口;
5)private dispatch queue是引用計數管理的,必須要retain與release語句,arc不需要;全局的不需要retain和release;
20.系統默認提供三個dispatch queue,它們的區別是優先級不同,通過如下方法可獲取:
dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
21.創建private queue語句爲:dispatch_queue_t queue = dispatch_queue_create("com.example.MyQueue", NULL);
22.絕對不要在任務中調用dispatch_sync或dispatch_sync_f函數,並同步dispatch新任務到當前正在執行的queue。對於串行 queue這一點特別重要,因 爲這樣做肯定會導致死鎖;
23.在dispatch queue中實現辦法是:Completion Block是你dispatch到queue的另一段代碼,在原始任務完成時自動執行。調用代碼在啓動任務時通過參數提供Completion Block。任務代碼只需要在完成工作時提交指定的Block或函數到指定的queue就實現了回調。
24.如果每次迭代執行的任務與其它迭代獨立無關,只是循環變量i++的值不同,而且循環迭代執行順序也無關緊要的話,你可以調用dispatch_apply或dispatch_apply_f函數來替換循環。它會自動把i的值迭代,如:
dispatch_apply(count, queue, ^(size_t i) { printf("%u\n",i);

});

25.使用dispatch_semaphore_create函數創建semaphore,指定正數值表示資源的可用數量;在每個任務中,調用dispatch_semaphore_wait來等待Semaphore;當上面調用返回時,獲得資源並開始工作;使用完資源後,調用dispatch_semaphore_signal函數釋放和signal這個semaphore。
26.dispatch group用來阻塞一個線程,直到一個或多個任務處理完成:基本流程是創建一個group,dispatch任務到queue時使用方法dispatch_group_async,將group和queue關聯起來,到後面需要等待任務處理完成的地方再調用dispatch_group_wait。
27.dispatch source用來在系統事件(定時器、系統信號量到達、文件與操作通知、進程相關事件等)觸發時,幫你把你所指定的代碼(塊或函數)提交到指定的dispatch queue中執行,需要你指定代碼塊或函數、queue和事件類型,該綁定不會自動取消,會一直等系統的事件,除非顯式取消關聯,同時爲了防止事件積壓,dispatch source實現了事件合併機制,新事件會替代或更新老事件;
28.gcd可替代自定義的Run loop而且更方便。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章