多線程學習

来源:http://www.cnblogs.com/busylife/archive/2016/11/21/6085931.html
-Advertisement-
Play Games

多線程學習 每一個iOS應用(進程)運行都會有一個主線程(UI線程),UI上的更新推薦在主線程中去完成。多線程本身並不複雜,難點在於多個線程在其生命周期的管理,如線程的執行順序、線程間的數據共用以及資源競爭等問題。 本文主要記錄開發中常用的3種多線程模式: NSThread NSOperation ...


多線程學習


每一個iOS應用(進程)運行都會有一個主線程(UI線程),UI上的更新推薦在主線程中去完成。多線程本身並不複雜,難點在於多個線程在其生命周期的管理,如線程的執行順序、線程間的數據共用以及資源競爭等問題。

本文主要記錄開發中常用的3種多線程模式:

  • NSThread
  • NSOperation
  • GCD

一、NSThread

NSThread是一種輕量級的多線程開發模式,使用起來也比較簡單主要通過一下兩個方法來創建新線程

+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;

- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0);
[NSThread start];

線程狀態分為3類:正在運行、已經完成、正在取消;可以用cancel來改變線程狀態,註意這並沒有真正的終止線程,除非調用其靜態方法[NSTread exist]來終止線程。

線程優先順序的範圍是0~1,值越大優先順序越高,線程預設值為0.5

NSObject分類 NSThreadPerformAdditions提供線程UI更新的主要方法如下:

//主線程才能更新UI
[self performSelectorOnMainThread:@selector(updateImageView:) withObject:imagedata waitUntilDone:YES];

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);

- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg NS_AVAILABLE(10_5, 2_0);

總結

  1. 使用簡單,但線程的執行順序很難控制;
  2. 需要自己管理線程的生命周期,一個任務創建一個線程占用系統開銷;

二、NSOperation

類似C#中的線程池,創建NSOperation放入NSOperationQueue隊列中一次啟動執行。NSOperation更加容易管理線程總數和線程之間的依賴關係。

NSOperation有兩個子類用於創建線程:NSInvocationOperationNSBlockOperation

// NSInvocationOperation創建

//創建NSOperation
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector() object:nil];
//創建操作隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//加入到隊列,開啟一個線程執行隊列中的線程
[queue addOperation:operation];



//NSBlockOperation創建

NSOperationQueue *queue = [[NSOperationQueue alloc]init];

//1、創建
    queue.maxConcurrentOperationCount = 5;
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
    
    }];
    [queue addOperation:operation];

//2、直接代碼塊加入隊列
[queue addOperationWithBlock:^{
       
}];

總結

  1. NSOperation可以設置最大併發數目;
  2. 可以設置依賴線程。假設線程A依賴線程B,操作隊列啟動後就會首先執行B再執行A,[operationA addDependency:OperationB]

三、GCD(Grand Central Dispatch)

基於C語言開發的一套多線程開發機制,也是蘋果推薦的多線程開發方法。這種機制最顯著的優點就是他對多核運算更佳有效。

GCD有一個類似NSOperationQueue的隊列,分為:

  • 串列隊列:只有一個線程,加入到隊列的操作依次執行。
  • 並行隊列:多個線程,將操作任務安排在可用的處理器上,同時保證先進來的任務先處理。
  • 主隊列:用於在主線程上執行的任務隊列,如UI更新。
//創建一個串列非同步隊列
    dispatch_queue_t serialQueue = dispatch_queue_create(@"queuename", DISPATCH_QUEUE_SERIAL);
    dispatch_async(serialQueue, ^{

    });
    
//UI更新
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_sync(mainQueue, ^{
    
});

併發隊列同樣是使用dispatch_queue_create()方法創建,只是最後一個參數指定為DISPATCH_QUEUE_CONCURRENT進行創建,但是在實際開發中我們通常不會重新創建一個併發隊列而是使用dispatch_get_global_queue()方法取得一個全局的併發隊列。

//創建一個全局並行非同步隊列
    dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(global, ^{

    });

GCD其他常用的執行方法:

  • dispatch_apply():重覆執行某個任務,但是註意這個方法沒有辦法非同步執行(為了不阻塞線程可以使用dispatch_async()包裝一下再執行)。
  • dispatch_once():單次執行一個任務,此方法中的任務只會執行一次,重覆調用也沒辦法重覆執行(單例模式中常用此方法)。
  • dispatch_time():延遲一定的時間後執行。
  • dispatch_barrier_async():使用此方法創建的任務首先會查看隊列中有沒有別的任務要執行,如果有,則會等待已有任務執行完畢再執行;同時在此方法後添加的任務必須等待此方法中任務執行後才能執行。(利用這個方法可以控制執行順序,例如前面先載入最後一張圖片的需求就可以先使用這個方法將最後一張圖片載入的操作添加到隊列,然後調用dispatch_async()添加其他圖片載入任務)
  • dispatch_group_async():實現對任務分組管理,如果一組任務全部完成可以通過6. dispatch_group_notify()方法獲得完成通知(需要定義dispatch_group_t作為分組標識)。

GCD的鎖機制

說到多線程就不得不提多線程中的鎖機制,多線程操作過程中往往多個線程是併發執行的,同一個資源可能被多個線程同時訪問,造成資源搶奪,這個過程中如果沒有鎖機制往往會造成重大問題。

  1. NSLock : 同步鎖NSLock來解決,使用時把需要加鎖的代碼(以後暫時稱這段代碼為”加鎖代碼“)放到NSLock的lock和unlock之間,一個線程A進入加鎖代碼之後由於已經加鎖,另一個線程B就無法訪問,只有等待前一個線程A執行完加鎖代碼後解鎖,B線程才能訪問加鎖代碼。

  2. @synchronized代碼塊:日常開發中也更推薦使用此方法。首先選擇一個對象作為同步對象(一般使用self),然後將”加鎖代碼”(爭奪資源的讀取、修改代碼)放到代碼塊中。@synchronized中的代碼執行時先檢查同步對象是否被另一個線程占用,如果占用該線程就會處於等待狀態,直到同步對象被釋放。

    //線程同步
    @synchronized(self){
        if (_imageNames.count>0) {
            name=[_imageNames lastObject];
            [NSThread sleepForTimeInterval:0.001f];
            [_imageNames removeObject:name];
        }
    }

GCD信號機制

在GCD中提供了一種信號機制,也可以解決資源搶占問題(和同步鎖的機制並不一樣)。GCD中信號量是dispatch_semaphore_t類型,支持 信號通知信號等待。每當發送一個信號通知,則信號量+1;每當發送一個等待信號時信號量-1,;如果信號量為0則信號會處於等待狀態,直到信號量大於0開始執行。根據這個原理我們可以初始化一個信號量變數,預設信號量設置為1,每當有線程進入“加鎖代碼”之後就調用信號等待命令(此時信號量為0)開始等待,此時其他線程無法進入,執行完後發送信號通知(此時信號量為1),其他線程開始進入執行,如此一來就達到了線程同步目的。

dispatch_semaphore_t _semaphore;//定義一個信號量
//初始化信號量參數
_semaphore = dispatch_semaphore_create(1);

//信號等待,第二個參數:等待時間 
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
if (_imageNames.count>0) {
      name=[_imageNames lastObject];
      [_imageNames removeObject:name];
}
//信號通知
dispatch_semaphore_signal(_semaphore);
        

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ...
  • <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, mi ...
  • <!-- ////////////////////////// 請款列表模板 開始--><div id="rtlist-temple"> <div class="list-box m-top-20"> <div class="list-title font-size-26 clearfix"> <s ...
  • 優美整潔的代碼,基本都需要遵循以下的幾大基本原則. 1.單一職責原則SRP (Single Responsibility Principle) 類,模塊,方法應該有且僅有一條修改的理由.也就是說,其僅僅負責一個功能,只有這個功能發生變化時,才需要修改它. 舉個慄子:人類 有 吃飯的方法,那麼這個方法 ...
  • 說到RecyclerView,相信大家都不陌生,它是我們經典級ListView的升級版,升級後的RecyclerView展現了極大的靈活性。同時內部直接封裝了ViewHolder,不用我們自己定義ViewHolder就能實現item的回收和復用功能。當然它肯定不止這些好處,比如我們可以自定義分割線,... ...
  • 1、打開CornerStone,找到偏號設置,找到Subversion選項 2、去看“Use default global ignores”前面的“勾”,刪除".a" 3、github上搜索“gitignore”,找到"Objective-C.gitignore",打開,對照著添加 4、添加以下幾項 ...
  • 一、寫在最前面 本次,來介紹一下安卓中為控制項--Button綁定事件的五種方式。 二、具體的實現 第一種:直接綁定在Button控制項上: 步驟1.在Button控制項上設置android:onClick=",其中這個屬性的屬性值對應的是MainActivity類中的方法名字(自己創建的方法): 步驟2 ...
  • 項目中經常需要底部彈出框,這裡我整理一下其中我用的比較順手的一個方式(底部彈出一個橫向滿屏的dialog)。 效果圖如下所示(只顯示關鍵部分): 步驟如下所示: 1.定義一個dialog的佈局(lay_share.xml) 1 <?xml version="1.0" encoding="utf-8" ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...