天天看點

iOS 程序、線程、多線程、多程序... 的認識iOS 程序、線程、多線程、多程序… 的認識

iOS 程序、線程、多線程、多程序… 的認識

基于對程序、線程的記憶模糊,為了提高自己的認知,查找了許多許多資料,做了一次彙總。

PS:

感謝廣大網友。原文連結: 簡書位址 。

一、程序

  • 程序是一個具有獨立功能的程式關于某次資料集合的一次運作活動,他是作業系統配置設定資源的基本機關。
  • 程序是指系統正在運作中的一個應用程式,就是一段程式執行的過程。我們可以了解為手機上的一個app。
  • 每個程序之間是獨立的,每個程序均運作在起專用且受保護的記憶體空間内,擁有獨立運作所需的全部資源。
  • 程序是作業系統進行資源配置設定的機關。

二、線程

  • 程式執行流的最小單元,線程是程序中的一個實體。
  • 一個程序想要執行任務,必須至少有一條線程。應用程式啟動的時候,系統會預設開啟一條線程,也就是主線程。

三、程序和線程的關系

  • 線程是程序的執行單元,程序的所有任務都線上程中執行。
  • 線程是

    CPU

    配置設定資源和排程的最小機關。
  • 一個程式可對應多個程序(多程序);一個程序中可對應多個線程,但至少要有一條線程。
  • 同個程序内的線程共享程序資源。

四、多程序

  • 程序是程式在計算機上的一次執行活動。當你運作一個程式,你就啟動了一個程序。顯然程式是死的(靜态的),程序是活動的(動态的)。
  • 程序可以分為系統程序和使用者程序。
    • 系統程序:凡是用于完成作業系統的各種功能的程序就是系統程序,他們就是出于運作狀态下的作業系統本身
    • 使用者程序:運作使用者程式時建立的運作在使用者态下的程序。
  • 程序又被細化為線程,也就是一個程序下有多個能獨立運作的更小的機關。在同一個時間裡,同一個計算機系統中如果允許兩個或兩個以上的程序處于運作狀态,這便是多程序。

五、多線程

  • 同一時間,CPU 隻能處理1條線程,隻有1條線程執行。多線程并發執行,其實是CPU快速地在多條線程之間排程(切換)。如果CPU的排程線程的時間足夠快,就造成了多線程并發執行的假象。
  • 如果線程非常至多(N條),CPU會在這些(N條)線程之間排程,消耗大量的CPU資源,每條線程被調用執行的頻率會降低(線程的執行效率降低)。
  • 多線程的有點:
    • 能适當提高程式的執行效率
    • 能适當提高資源的使用率(CPU、記憶體使用率)
  • 多線程的缺點:
    • 開啟線程需要占用一定的記憶體空間(預設情況下,主線程占用1M,子線程占用512kb),如若開啟大量線程,會占用大量的記憶體空間,就會降低程式的性能
    • 線程越多,CPU在排程線程的開銷就越大
    • 程式設計更加複雜:如線程之間的通信、多線程之間的資料共享等

六、任務

就是執行操作的意思,也就是線上程中執行的那段代碼。在DCD中是放在block 中的。

執行任務的方式有兩種:

同步執行(sync)

異步執行(async)

  • 同步(Sync): 同步添加任務到指定的隊列中,在添加的任務執行結束之前,會一直等待,直到隊列中的任務都完成之後再執行,是以會阻塞線程。 隻能在目前線程中執行任務(是目前的線程,不一定是主線程),不具備開啟新線程的能力。
  • 異步(Async): 線程會立即傳回,無需等待就會繼續執行下面的任務,不會阻塞目前線程。可以線上的線程中執行任務,具備開啟線程的能力(具備但不是一定要開啟新線程)。如果不是添加在主隊列上,異步會在子線程中執行任務。

七、 隊列

隊列(Dispatch Queue): 這裡的隊列是指執行任務的等待隊列,即用來存放任務的隊列。

隊列是一種特殊的線性表,遵循

FIFO(先進先出)

的原則,即隻能在隊尾插入,隊頭删除。 沒讀取一個任務,則從隊列中釋放(删除)一個任務。

在GCD中有兩種隊列:

串行隊列

并發隊列

。兩者都符合

FIFO

的原則,二者的主要差別是:執行的順序不同和開啟的線程數不同。

  • 串行隊列(Serial Dispatch Queue):

    同一時間内,隊列中隻能執行一個任務,隻有目前的任務執行完成之後,才能執行下一個任務。(隻能開啟一個線程,一個線程執行完畢後,再執行下一個任務)。主隊列是主線程上的一個串行隊列,是系統自動為程式建立的

  • 并行隊列(Concurrent Dispatch Queue):

    同時允許多個任務同時執行。(可以開啟多個線程,并且同時執行)。并發隊列的并發功能隻有在異步(dispatch_async) 函數下才有效。

八、iOS 中的多線程

主要有三種:NSThread、NSOperationQueue、GCD

  1. NSThread: 輕量級别的多線程技術
    • 手動開辟的子線程,使用的是初始化方式:那麼就需要我們自己啟動
    • 手動開辟的子線程,使用的是構造器方式:那麼它就會自動啟動
    • 隻要是我們手動開辟的子線程,都需要我們自己管理,包括該線程啟動和使用完畢後的資源回收。
      NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(testThread:) object:@"我是參數"];
          // 當使用初始化方法出來的主線程需要start啟動
          [thread start];
          // 可以為開辟的子線程起名字
          thread.name = @"NSThread線程";
          // 調整Thread的權限 線程權限的範圍值為0 ~ 1 。越大權限越高,先執行的機率就會越高,由于是機率,是以并不能很準确的的實作我們想要的執行順序,預設值是0.5
          thread.threadPriority = 1;
          // 取消目前已經啟動的線程
          [thread cancel];
          // 通過周遊構造器開辟子線程
          [NSThread detachNewThreadSelector:@selector(testThread:) toTarget:self withObject:@"構造器方式"];
                 
    • performSelector… 隻要是

      NSObject

      的子類或者對象,都可以通過調用該方法進入子線程和主程。其實這些方法所開辟的子線程也是 NSThread 的另一種展現方式。

      注意:在編譯階段并不會去檢查方式是否有效存在,如果不存在隻會給出警告

      //在目前線程。延遲1s執行。響應了OC語言的動态性:延遲到運作時才綁定方法
              [self performSelector:@selector(aaa) withObject:nil afterDelay:1];
            // 回到主線程。waitUntilDone:是否将該回調方法執行完在執行後面的代碼,如果為YES:就必須等回調方法執行完成之後才能執行後面的代碼,說白了就是阻塞目前的線程;如果是NO:就是不等回調方法結束,不會阻塞目前線程
              [self performSelectorOnMainThread:@selector(aaa) withObject:nil waitUntilDone:YES];
            //開辟子線程
              [self performSelectorInBackground:@selector(aaa) withObject:nil];
            //在指定線程執行
              [self performSelector:@selector(aaa) onThread:[NSThread currentThread] withObject:nil waitUntilDone:YES]
                 

      **需要注意的是:**

      如果帶有

      afterDelay

      延時參數時,會在内部建立一個 NSTimer , 然後添加到目前線程的 Runloop 中。也就是如果目前線程沒有開啟 runloop ,該方法就會失效。在子線程中,需要啟動runloop(注意調用順序)。
      [self performSelector:@selector(aaa) withObject:nil afterDelay:1];
      [[NSRunLoop currentRunLoop] run];
                 

      perfromSelector:withObject:

      隻是一個單純的消息發送,和時間沒有關系,是以不需要添加在子線程的 runloop 也可以執行。
  2. GCD 對比 NSOperationQueue

二者之間的關系:

GCD 是面向底層的C語言的API, NSOperationQueue 使用 GCD 建構封裝的,是GCD的進階抽象。

  • GCD 的執行效率更高。而且由于隊列中執行的是由block構成的任務,這個一個輕量級的資料結構,寫起來更友善
  • GCD 隻支援FIFO的隊列,而NSOperationQueue可以通過設定最大并發數,設定優先級,添加依賴關系等調整執行順序
  • NSOperationQueue 甚至可以設定跨隊列依賴關系,但是GCD 隻能通過設定串行隊列,或者在隊列内添加barrier(dispaych_barrier_async)任務,才能控制執行順序,較為複雜
  • NSOperationQueue 因為面向對象,是以支援KVO,可以檢測 operation 是否正在執行(isExecuted)、是否結束(isFinished)、是否取消(isCanceld)
    • 實際項目中,很多時候隻是用到異步操作,不會有特别複雜的線程關系管理,一所GCD 是蘋果推薦的優選項
    • 如果考慮異步操作之間的事務性、順序性、依賴關系,比如多線程并發下載下傳,GCD需要寫更多的代碼,而NSOperationQueue 已經内建了這些支援
    • 不論是GCD 還是NSOperationQueue,我們接觸的都是任務和隊列,都沒有直接接觸到線程,事實上線程的管理也的确不需要我們操心,系統對于線程的建立,排程管理和釋放都做得很好。而NSThread 需要我們自己去管理線程的生命周期,還要考慮線程的同步、加鎖問題,造成一些性能上的開銷。