1. 程式人生 > >iOS多執行緒中,佇列和執行的排列組合結果分析

iOS多執行緒中,佇列和執行的排列組合結果分析

本文是對以往學習的多執行緒中知識點的一個整理。

多執行緒中的佇列有:序列佇列,併發佇列,全域性佇列,主佇列

執行的方法有:同步執行和非同步執行。那麼兩兩一組合會有哪些注意事項呢?

如果不是在董鉑然部落格園看到這邊文章請 點選檢視原文

提到多執行緒,也就是四種,pthread,NSthread,GCD,NSOperation  

其中phtread是跨平臺的。GCD和NSOperation都是常用的,後者是基於前者的。

但是兩者區別:GCD的核心概念是將一個任務新增到佇列,指定任務執行的方法,然後執行。 NSOperation則是直接將一個操作新增到佇列中。

為了整體結構更加清晰,我是用GCD來做此排列組合的實驗。實驗主要是通過迴圈內列印和主執行緒的列印先後順序來判斷結果,最後再加以總結

1.序列佇列,同步執行

    dispatch_queue_t q = dispatch_queue_create("dantesx", NULL);
    
    // 執行任務
    for (int i = 0; i<10; i++) {
        dispatch_sync(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
    
    NSLog(@"董鉑然 come here");

執行效果:

 

執行結果可以清楚的看到全在主執行緒執行,並且是按照數序執行,迴圈結束之後主執行緒的列印才輸出。

2.序列佇列,非同步執行

    dispatch_queue_t q = dispatch_queue_create("dantesx", NULL);
    
    for (int i = 0; i<10; i++) {
        dispatch_async(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
    //    [NSThread sleepForTimeInterval:0.001];
    NSLog(@"董鉑然 come here");

 執行結果

結果顯示,系統開了1條非同步執行緒,因此全部線上程2執行,並且是順序執行。主執行緒列印雖然在最上面,但是這個先後順序是不確定,如果睡個0.001秒,主執行緒的列印會混在中間。

3.併發佇列,非同步執行

    // 1. 佇列
    dispatch_queue_t q = dispatch_queue_create("dantesx", DISPATCH_QUEUE_CONCURRENT);
    
    // 2. 非同步執行
    for (int i = 0; i<10; i++) {
        dispatch_async(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
    //    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"董鉑然 come here");

 執行結果

結果顯示,主執行緒的列印還是混在中間不確定的,因為非同步執行緒就是誰也不等誰。系統開了多條執行緒,並且執行的順序也是亂序的

4.併發佇列,同步執行

    // 1. 佇列
    dispatch_queue_t q = dispatch_queue_create("dantesx", DISPATCH_QUEUE_CONCURRENT);
    
    // 2. 同步執行
    for (int i = 0; i<10; i++) {
        dispatch_sync(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
    //    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"董鉑然 come here");

 執行結果

這個執行結果和第1種的序列佇列,同步執行是一模一樣的。 因為同步任務的概念就是按順序執行,後面都要等。言外之意就是不允許多開執行緒。 同步和非同步則是決定開一條還是開多條。

所以一旦是同步執行,前面什麼佇列已經沒區別了

5.主佇列,非同步執行

    // 1. 主佇列 - 程式啟動之後已經存在主執行緒,主佇列同樣存在
    dispatch_queue_t q = dispatch_get_main_queue();
    // 2. 安排一個任務
    for (int i = 0; i<10; i++) {
        dispatch_async(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
    NSLog(@"睡會");
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"董鉑然 come here");

 執行結果

結果顯示有點出人意料。主執行緒在睡會之後才打印,迴圈一直在等著。因為主佇列的任務雖然會加到主執行緒中執行,但是如果主執行緒裡也有任務就必須等主執行緒任務執行完才輪到主佇列的。

6.主佇列,同步執行

    dispatch_queue_t q = dispatch_get_main_queue();
    
    NSLog(@"卡死了嗎?");
    
    dispatch_sync(q, ^{
        NSLog(@"我來了");
    });
    
    NSLog(@"董鉑然 come here");

 執行結果為卡死

卡死的原因是迴圈等待,主佇列的東西要等主執行緒執行完,而因為是同步執行不能開執行緒,所以下面的任務要等上面的任務執行完,所以卡死。這是排列組合中唯一一個會卡死的組合。

7.同步任務的使用場景

    dispatch_queue_t q = dispatch_queue_create("dantesx", DISPATCH_QUEUE_CONCURRENT);
    // 1. 使用者登入,必須要第一個執行
    dispatch_sync(q, ^{
        [NSThread sleepForTimeInterval:2.0];
        NSLog(@"使用者登入 %@", [NSThread currentThread]);
    });
    // 2. 扣費
    dispatch_async(q, ^{
        NSLog(@"扣費 %@", [NSThread currentThread]);
    });
    // 3. 下載
    dispatch_async(q, ^{
        NSLog(@"下載 %@", [NSThread currentThread]);
    });
    NSLog(@"董鉑然 come here");

 執行結果

結果顯示,“使用者登陸”在主執行緒列印,後兩個在非同步執行緒列印。上面的“使用者登陸”使用同步執行,後面的扣費和下載都是非同步執行。所以“使用者登陸”必須第一個打印出來不管等多久,然後後面的兩個非同步和主執行緒列印會不確定順序的列印。這就是日常開發中,那些後面對其有依賴的必須要先執行的任務使用同步執行,然後反正都要執行先後順序無所謂的使用非同步執行。

8.block非同步任務包裹同步任務

    dispatch_queue_t q = dispatch_queue_create("dantesx", DISPATCH_QUEUE_CONCURRENT);
    void (^task)() = ^ {
        // 1. 使用者登入,必須要第一個執行
        dispatch_sync(q, ^{
            NSLog(@"使用者登入 %@", [NSThread currentThread]);
        });
        // 2. 扣費
        dispatch_async(q, ^{
            NSLog(@"扣費 %@", [NSThread currentThread]);
        });
        // 3. 下載
        dispatch_async(q, ^{
            
            NSLog(@"下載 %@", [NSThread currentThread]);
        });
    };
    
    dispatch_async(q, task);
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"董鉑然 come here");

 執行結果

因為整個block是在非同步執行的,所以即使裡面“使用者登陸”是同步執行,那也無法在主執行緒中執行,只能開一條非同步執行緒執行,因為是同步的所以必須等他先執行,後面的“扣費”和“下載”在上面同步執行結束之後,不確定順序的列印。

9.全域性佇列

    dispatch_queue_t q = dispatch_get_global_queue(0, 0);
    
    for (int i = 0; i < 10; i++) {
        dispatch_async(q, ^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        });
    }
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"com here");

 執行結果

全域性佇列的本質就是併發佇列,只是在後面加入了,“服務質量”,和“排程優先順序” 兩個引數,這兩個引數一般為了系統間的適配,最好直接填0和0

如果不是在董鉑然部落格園看到這邊文章請 點選檢視原文

總結:

1. 開不開執行緒,取決於執行任務的函式,同步不開,非同步開。

2. 開幾條執行緒,取決於佇列,序列開一條,併發開多條(非同步)

3. 主佇列:  專門用來在主執行緒上排程任務的"佇列",主佇列不能在其他執行緒中排程任務!

4. 如果主執行緒上當前正在有執行的任務,主佇列暫時不會排程任務的執行!主佇列同步任務,會造成死鎖。原因是迴圈等待

5. 同步任務可以佇列排程多個非同步任務前,指定一個同步任務,讓所有的非同步任務,等待同步任務執行完成,這是依賴關係。

6. 全域性佇列:併發,能夠排程多個執行緒,執行效率高,但是相對費電。 序列佇列效率較低,省電省流量,或者是任務之間需要依賴也可以使用序列佇列。

7. 也可以通過判斷當前使用者的網路環境來決定開的執行緒數。WIFI下6條,3G/4G下2~3條。

相關推薦

iOS執行佇列執行排列組合結果分析

本文是對以往學習的多執行緒中知識點的一個整理。 多執行緒中的佇列有:序列佇列,併發佇列,全域性佇列,主佇列。 執行的方法有:同步執行和非同步執行。那麼兩兩一組合會有哪些注意事項呢? 如果不是在董鉑然部落格園看到這邊文章請 點選檢視原文 提到多執行緒,也就是四種,pthread,NSthread,GCD

Java執行JoinInterrupt()方法的使用

更多詳細的解答請轉至:http://my.oschina.net/summerpxy/blog/198457;http://uule.iteye.com/blog/1101994;(比如有一個執行緒t.當在Main執行緒中呼叫t.join()的時候,那麼Main執行緒必須拿

(四)執行說學逗唱:執行險惡變數執行安全不得不防

(一)多執行緒說學逗唱:關於執行緒那不得不說的二三事 (二)多執行緒說學逗唱:新手村偶遇Thread類 (三)多執行緒說學逗唱:村口的老R頭是個掃地僧(Runnable) 出了新手村,以後的路可就不那麼好走了,到底現在也是個江湖人,都必須經歷點困難挫折,要不以後拿什

執行總記憶體執行的工作記憶體

Java記憶體模型將記憶體分為了 主記憶體和工作記憶體 。類的狀態,也就是類之間共享的變數,是儲存在主記憶體中的,每個執行緒都有一個自己的工作記憶體(相當於CPU高階緩衝區,這麼做的目的還是在於進一步縮小儲存系統與CPU之間速度的差異,提高效能),每次Java

4.iOS執行GCD技術的佇列執行方式的組合結果

本文是對以往學習的多執行緒中知識點的一個整理。 多執行緒中的佇列有:序列佇列,併發佇列,全域性佇列,主佇列。 執行的方法有:同步執行和非同步執行。那麼兩兩一組合會有哪些注意事項呢? 如果不是在董鉑然部落格園看到這邊文章請 點選檢視原文 提到多執行緒,也就是四種,pthread,NSthread,G

boostasio網路庫執行併發處理實現以及asio在執行模型執行的排程情況執行安全。

1、實現多執行緒方法: 其實就是多個執行緒同時呼叫io_service::run         for (int i = 0; i != m_nThreads; ++i)         {             boost::shared_ptr<boost::

Java執行Synchronized簡介Static Synchronized的區別

在進行Java開發時,多執行緒的開發是經常會使用的。首先會問一個小問題啊,在Java中有幾種方法可以建立一個執行緒? 我給的答案是3種。(如果還有其他的請留言告訴我哈。) 1、建立直接繼承自Thread類建立執行緒子類。   步驟如下:a 定義一個子類,同時

執行佇列不一定需要執行安全

兩個執行緒,主執行緒中update update(){   while(queue.count >0){     //process....     queue.pop()   } }   子執行緒中: queue.enqueue(data)   這樣做是沒有問

tensorflow佇列執行

一、佇列 tensorflow中主要有FIFOQueue和RandomShuffleQueue兩種佇列,下面就詳細介紹這兩種佇列的使用方法和應用場景。 1、FIFOQueue FIFOQueue是先進先出佇列,主要是針對一些序列樣本。如:在使用迴圈神經網路的時候,需要處理語音、文字、

QT執行物件訊號與槽連線不上的解決辦法

1、在接收者建立執行緒中,把接收者移動到主執行緒中: pReceiverObj->moveToThread(QApplication::instance()->thread()); 2、這樣傳送訊號的時候,就會在主執行緒事件佇列處理中來處理了。 把connect的最

執行池ThreadPoolExecutor分析: 執行池是什麼時候建立執行佇列的任務是什麼時候取出來的?

  帶著幾個問題進入原始碼分析: 執行緒池是什麼時候建立執行緒的? 任務runnable task是先放到core到maxThread之間的執行緒,還是先放到佇列? 佇列中的任務是什麼時候取出來的? 什麼時候會觸發reject策略? core到maxThread之間的執行緒什麼時候會di

Java執行的finalstatic

看Android的多執行緒發現其實是Java的多執行緒。我找了一本Java程式設計思想學習Java的併發機制。寫了一個demo,遇到一些問題,雖然最後想明白了,但是也暴露了我的Java基礎差勁的事實。之後我會通過寫部落格的方式來提高Java水平。現在說一下我的問

C++ Boost 執行(九)生產者消費者問題

#include <iostream> #include <boost/thread.hpp> using namespace std; class Account { pu

執行的wait()notify()方法

wait()和notify()方法屬於Object類中的方法,是用於對執行緒之間進行資源物件鎖的通訊,其必須在synchronized(Obj){...}語法塊內 wait()就是說執行緒在獲取物件鎖後,主動釋放物件鎖,同時本執行緒進行休眠。直到有其它執行緒呼叫該物件的no

在 Java 的執行如何去判斷給定的一個類是否是執行安全的(另外:synchronized 同步是否就一定能保證該類是執行安全的。)

同步程式碼塊和同步方法的區別:同步程式碼塊可以傳入任意物件,同步方法中 如果多個執行緒檢查的都是一個新的物件,不同的同步鎖對不同的執行緒不具有排他性,不能實現執行緒同步的效果,這時候執行緒同步就失效了。   兩者的區別主要體現在同步鎖上面。對於例項的同步方法,因為只能使用

Java 執行。兩個執行交替執行一個輸出偶數一個輸出奇數(方法二)

package com.up366.thread.example; import java.util.concurrent.Semaphore; /** * Java 多執行緒中。兩個執行緒交替執

Java 執行。兩個執行交替執行一個輸出偶數一個輸出奇數(方法一)

public class DigitPrinterExample { public static void main(String[] args) { Number num =

java之執行Thread類Runnable介面使用方法

java提供了兩種執行緒方式,一種是繼承java.lang包下的Thread類,覆寫Thread類的run()方法,在run()方法中實現執行線上程上的程式碼!第二種是實現Runnable介面建立多執行

執行wait(),notify()notifyall()方法的含義

在“synchronized(obj){··········}”這個同步塊中,obj物件叫做監控器,只有持有監控器這個物件的鎖時才會執行同步塊中的內容Java中的執行緒的生命週期大體可分為5種狀態。1. 新建(NEW):新建立了一個執行緒物件。2. 可執行(RUNNABLE)

Spring 在執行bean的注入問題(轉部落格園)

最近碰到了一個問題,使用SSM框架,在Service層需要另開一個執行緒,這個執行緒專門用來做一些操作,並將結果寫入資料庫中。但是線上程中使用@Resource或者@Autowired注入全部為NULL,原來是Spring不能線上程中注入。網上的主要解決方法有:將需要的Bean作為執行緒的的建構函式的引數傳入