iOS開發之多線程技術

来源:http://www.cnblogs.com/Jepson1218/archive/2016/02/03/5180196.html
-Advertisement-
Play Games

本篇爭取一篇講清講透,依然將通過四大方面清晰的對iOS開發中多線程的用法進行詳盡的講解: 一、什麼是多線程 1)多線程執行原理 2)線程與進程 3)多線程的優缺點 二、我們為什麼要用多線程編程技術 三、如何使用多線程技術 1)pthread技術 2)NSThread技術 2.1)線程屬性 2.2)資


本篇爭取一篇講清講透,依然將通過四大方面清晰的對iOS開發中多線程的用法進行詳盡的講解:

一、什麼是多線程

  1)多線程執行原理

  2)線程與進程

  3)多線程的優缺點

二、我們為什麼要用多線程編程技術

三、如何使用多線程技術

1)pthread技術

2)NSThread技術

2.1)線程屬性

2.2)資源共用(搶奪)

3)GCD技術

4) NSOperation技術

四、線程的生命周期(線程狀態)

 


一、什麼是多線程

  多線程(英語:multithreading),是指從軟體或者硬體上實現多個線程併發執行的技術。具有多線程能力的電腦因有硬體支持而能夠在同一時間執行多於一個線程,進而提升整體處理性能。具有這種能力的系統包括對稱多處理機、多核心處理器以及晶元級多處理(Chip-level multithreading)或同時多線程(Simultaneous multithreading)處理器。在一個程式中,這些獨立運行的程式片段叫作“線程”(Thread),利用它編程的概念就叫作“多線程處理(Multithreading)”。具有多線程能力的電腦因有硬體支持而能夠在同一時間執行多於一個線程(臺灣譯作“執行緒”),進而提升整體處理性能。

  1) 多線程執行原理

  

  a. (單核CPU)同一時間,cpu只能處理1個線程,只有1個線程在執行

  b. 多線程同時執行:是CPU快速的在多個線程之間的切換

  c. cpu調度線程的時間足夠快,就造成了多線程的"同時"執行

  d. 如果線程數非常多,cpu會在n個線程之間切換,消耗大量的cpu資源

  i. 每個線程被調度的次數會降低,線程的執行效率降低

  2)線程與進程

  每個正在系統上運行的程式都是一個進程。每個進程包含一到多個線程。進程也可能是整個程式或者是部分程式的動態執行。線程是一組執行的集合,或者是程式的特殊段,它可以在程式里獨立執行。也可以把它理解為代碼運行的上下文。所以線程基本上是輕量級的進程,它負責在單個程式里執行多任務。通常由操作系統負責多個線程的調度和執行。

  線程是程式中一個單一的順序控制流程,在單個程式中同時運行多個線程完成不同的工作,稱為多線程。

  線程和進程的區別在於,子進程和父進程有不同的代碼和數據空間,而多個線程則共用數據空間,每個線程有自己的執行堆棧和程式計數器為其執行上下文,多線程主要是為了節約CPU時間,發揮利用,根據具體情況而定。線程的運行中需要使用電腦的記憶體資源和CPU。  

  3)多線程的優缺點

  優點:

    1、使用線程可以把占據時間長的程式中的任務放到後臺去處理。

    2、用戶界面可以更加吸引人,這樣比如用戶點擊了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理的進度。  

    3、程式的運行速度可能加快。

    4、在一些等待的任務實現上如用戶輸入、文件讀寫和網路收發數據等,線程就比較有用了。在這種情況下可以釋放一些珍貴的資源如記憶體占用等等。

    5、線程上的任務執行完成後,線程會自動銷毀。

  缺點:

    1、線程越多,cpu在調用線程上的開銷就越大,如果有大量的線程,會影響性能,因為操作系統需要在它們之間切換。

    2、開啟線程需要占用一定的記憶體空間(預設情況下,每一個線程都占512KB),如果開啟大量的線程,會占用大量的記憶體空間,降低程式的性能,更多的線程需要更多的記憶體空間。

    3、程式設計更加複雜,比如線程間的通信、多線程的數據共用,可能會給程式帶來更多的BUG,因此要小心使用。

    4、線程的中止需要考慮其對程式運行的影響。

    5、通常塊模型數據是在多個線程間共用的,需要一個合適的鎖系統替換掉數據共用。

  

  註意:iOS 8.0後主線程的預設堆棧大小也是 512K,官方文檔標註錯誤。

 


二、我們為什麼要用多線程編程技術

  在大多數研究領域內是要求線程調度程式要能夠快速選擇其中一個已就緒線程去運行,而不是一個一個運行而降低效率。所以要讓調度程式去分辨線程的優先順序是很重要的。在移動開發過程中,一切均已用戶體驗作為首要任務,這時多線程的重要性不言而喻。

  一個程式運行後,預設會開啟1個線程,稱為“主線程”或“UI線程”,主線程一般用來刷新UI界面,處理UI事件(比如:點擊、滾動、拖拽等事件)

  主線程使用註意

    別將耗時的操作放到主線程中

    耗時操作會卡住主線程,嚴重影響UI的流暢度,給用戶一種卡的壞體驗

 


三、如何使用多線程技術

ios中多線程實現的多種技術方案:

POSIX 表示可移植操作系統介面(Portable Operating System Interface )-----pthread

 

1)pthread技術:

pthread 是 POSIX 多線程開發框架,由於是跨平臺的 C 語言框架,在蘋果的頭文件中並沒有詳細的註釋要查閱 pthread 有關資料,可以訪問 http://baike.baidu.com

// 創建線程,並且線上程中執行 demo 函數
- (void)pthreadDemo {

    /**
     參數:
     1> 指向線程標識符的指針,C 語言中類型的結尾通常 _t/Ref,而且不需要使用 *
     2> 用來設置線程屬性
     3> 新建立的線程執行代碼的函數
     4> 運行函數的參數

     返回值:
     - 若線程創建成功,則返回0
     - 若線程創建失敗,則返回出錯編號

     在混合開發時,如果在 C 和 OC 之間傳遞數據,需要使用 __bridge 進行橋接,橋接的目的就是為了告訴編譯器如何管理記憶體
     */
    pthread_t threadId = NULL;
    NSString *str = @"Hello Pthread";

    int result = pthread_create(&threadId, NULL, demo, (__bridge void *)(str));

    result ? NSLog(@"為其他任何值時代表開闢子線程失敗") : NSLog(@"當result為0時表示開闢子線程成功");
}

// 後臺線程調用函數
void *demo(void *params) {
    NSString *str = (__bridge NSString *)(params);

    NSLog(@"%@ - %@", [NSThread currentThread], str);

    return NULL;
}
C語言中pthread.h里pthread實現多線程

 

2)NSThread技術:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSLog(@"主線程%@", [NSThread currentThread]);
    /**
     多個線程之間的執行順序是隨機的
     */
    
    // 方式1:通過NSThread的對象方法
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(demo:) object:@"方式1"];
    [thread start];
    
    // 方式2:沒有thread字眼,隱式創建並啟動線程,所有 NSObject 都可以使用此方法,在其他線程執行方法
    [self performSelectorInBackground:@selector(demo:) withObject:@"方式2"];
    
    // 方式3:detachNewThreadSelector 類方法不需要啟動,會自動創建線程並執行 @selector 方法
    [NSThread detachNewThreadSelector:@selector(demo:) toTarget:self withObject:@"方式3"];
    
}

- (void)demo:(NSString *)str {
    NSLog(@"%@, %@", str, [NSThread currentThread]);
}
通過NSThread創建線程的三種方式

 

2.1)線程屬性

1. name - 線程名稱
2. threadPriority - 線程優先順序
  取值範圍從 0~1.0
  1.0表示優先順序最高
  0.0表示優先順序最低
  預設優先順序是0.5
3. stackSize - 棧區大小
4. isMainThread - 是否主線程

 

2.2)資源共用(搶奪)

  1塊資源可能會被多個線程共用,也就是多個線程可能會訪問同一塊資源,比如多個線程訪問同一個對象、同一個變數、同一個文件當多個線程訪問同一塊資源時,很容易引發數據錯亂和數據安全問題。如購買火車票問題:

  解決方案:

#pragma mark
#pragma mark - 模擬賣票系統
- (void)sellTicket {
    
    _count = 50;
    
    NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(ticket) object:nil];
    thread1.name = @"t1";
    [thread1 start];
    
    NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(ticket) object:nil];
    thread2.name = @"t2";
    [thread2 start];
}

- (void)ticket {
    
    while (YES) {
        
        // 被加鎖的對象
        @synchronized(self) {
            if (_count > 0) {
                _count = self.count - 1;
                NSLog(@"剩餘票數%ld ——%@", _count, [NSThread currentThread]);
            } else {
                NSLog(@"票賣沒了倒霉蛋");
                break;
            }
        }
    }
    
}
賣票系統線程同步解決線程不安全問題

 

  • 互斥鎖:如果發現有其他線程正在執行鎖定的代碼,線程會進入休眠狀態,等待其他線程執行完畢,打開鎖之後,線程會被喚醒
  • 自旋鎖:如果發現有其他線程正在執行鎖定的代碼,線程會以死迴圈的方式,一直等待鎖定代碼執行完成

  線程安全

多個線程進行讀寫操作時,仍然能夠得到正確結果,被稱為線程安全,要實現線程安全,必須要用到鎖、
為了得到更佳的用戶體驗,UIKit 不是線程安全的,所以更新 UI 的操作都必須主線程上執行!因此,主線程又被稱為UI 線程。

 

3)GCD技術

  為保證篇幅不過與雜糅,請見“IOS開發之多線程技術——GCD篇

   

4) NSOperation技術

  為保證篇幅不過與雜糅,請見“IOS開發之多線程技術——NSOperation篇

 


四、線程的生命周期(線程狀態)

新建

  實例化線程對象

就緒

  - (void)start;

  向線程對象發送 start 消息,線程對象被加入 可調度線程池 等待 CPU 調度
  detachNewThreadSelector 方法和 performSelectorInBackground 方法會直接實例化一個線程對象並加入 可調度線程池
運行
  CPU 負責調度可調度線程池中線程的執行
  線程執行完成之前(死亡之前),狀態可能會在就緒和運行之間來回切換
  就緒和運行之間的狀態變化由 CPU 負責,程式員不能幹預
阻塞
  當滿足某個預定條件時,可以使用休眠或鎖阻塞線程執行

  + (void)sleepUntilDate:(NSDate *)date;

  + (void)sleepForTimeInterval:(NSTimeInterval)ti;

  @synchronized(self):互斥鎖
死亡:+ (void)exit

  正常死亡
  線程執行完畢
  非正常死亡
  當滿足某個條件後,線上程內部自己中止執行(自殺),[NSThread exit];
  當滿足某個條件後,在主線程給其它線程打個死亡標記(下聖旨),讓子線程自行了斷.(被逼著死亡)

  註意:在終止線程之前,應該註意釋放之前分配的對象!


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

-Advertisement-
Play Games
更多相關文章
  • $.extend()和$.fn.extend()函數用法簡單介紹:標題中的兩個方法在jQuery插件開發中非常的重要,下麵通過簡單的代碼實例介紹一下它們的用法。本章節不會介紹它的原理,而是只給出它們的作用是什麼,能夠做什麼事情。jQuery.extend()可以為jQuery類添加新的方法,類似於c
  • javascript如何設置指定標簽的透明度:在實際應用中,可能需要動態的設置標簽的透明度,現在就以div為例子介紹一下如何實現此效果。代碼實例如下: <!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <meta name="author"
  • body在預設情況下是具有margin外邊距的:這裡只是陳述一個事實,那就是body具有外邊距在預設情況下。代碼實例如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="author" content="http:/
  • 本篇將從四個方面對iOS開發中使用到的NSOperation技術進行講解: 一、什麼是NSOperation 二、我們為什麼使用NSOperation 三、在實際開發中如何使用NSOperation 1、自定義NSOperation 2、NSOperation的基本使用 3、NSOperation實
  • 分類:C#、Android; 日期:2016-02-04 3.5 示例5--多地圖展示 一、簡介 地圖控制項自v2.3.5版本起,支持多實例,即開發者可以在一個頁面中建立多個地圖對象,並且針對這些對象分別操作且不會產生相互干擾。 文件名:Demo04MultiMapView.cs 簡介:介紹多MapV
  • 本篇將從四個方面對iOS開發中GCD的使用進行詳盡的講解: 一、什麼是GCD 二、我們為什麼要用GCD技術 三、在實際開發中如何使用GCD更好的實現我們的需求 一、Synchronous & Asynchronous 同步 & 非同步 二、Serial Queues & Concurrent Queu
  • Android編譯過程中遇到的難題及解決方案。
  • UIViewAutoresizingNone = 0, UIViewAutoresizingFlexibleLeftMargin = 1 << 0, UIViewAutoresizingFlexibleWidth = 1 << 1, UIViewAutoresizingFlexibleRightMa
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...