多線程單線程,同步異步,並發並行,串行隊列並行隊列,看這里就對了


多線程開發用了很久,但是一直沒去深入了解。長久以來一直有一些迷惑。直到深入了解后,才發現了以前的理解有不少錯誤的地方。

單線程等於同步,多線程等於異步

  • 這種理解很直觀,畢竟只有一個線程怎么異步?

Node.js表示不服,我就是單線程,我也能異步。談一談Node中的異步和單線程
看完這篇文章我明白了單線程也能異步,把IO等耗時的操作比作燒水,我可以在這個時候切菜,這就是異步啊。
等等,似乎有點不對,那io又誰來開啟,又誰來通知cpu我已經結束了呢?
Node.js異步IO的實現,這篇文章解決了我的疑惑。

  • Node.js里面只有自己寫的代碼是跑在主線程上,但是內部並不是單線程的,由C編寫的底層開啟了線程做IO操作。

恍然大悟,我現在的理解就是,會有一個可運行的線程池在等待cpu的使用權。類似IO,網絡請求這種耗時干等的操作,線程會放到需要等待的線程池中(阻塞),不會獲取cpu的使用權,直到操作完成

這個理解了,並發和並行就很容易了。

  • 每個線程獲得cpu的使用權的時間就是一個時間片,用完了就必須要等下次了。時間片非常短,人根本意識不到,感覺就是並行的,但其實只是"偽並行",也就是並發。

概念都講結束了,現在可以談談iOS的多線程了。其實理論都一樣,無非線程的獲得,開啟,結束等。但是iOS有個不同,他有GCD,那真是神器。
關於GCD的串行隊列,並行隊列,一直以來都有一個錯誤的理解:

隊列就是線程,async就是另開線程,sync就是阻塞線程

實踐才能出真知,要想真明白,async,sync,串行隊列,並行隊列,主隊列,還是要親自測一下才行。

  • 主線程下,是否開啟新線程
//主隊列
dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"%@",[NSThread currentThread]);
});
    
dispatch_sync(dispatch_get_main_queue(), ^{
    NSLog(@"%@",[NSThread currentThread]);
});

//串行隊列
dispatch_queue_t ser_queue = dispatch_queue_create("串行", DISPATCH_QUEUE_SERIAL);
    
dispatch_async(ser_queue, ^{
    NSLog(@"1-%@",[NSThread currentThread]);
});

dispatch_async(ser_queue, ^{
    NSLog(@"2-%@",[NSThread currentThread]);
});
    
dispatch_sync(ser_queue, ^{
    NSLog(@"3-%@",[NSThread currentThread]);
});

//並行隊列
dispatch_queue_t con_queue = dispatch_queue_create("並行", DISPATCH_QUEUE_CONCURRENT);
    
dispatch_async(con_queue, ^{
    NSLog(@"1-%@",[NSThread currentThread]);
});

dispatch_async(con_queue, ^{
    NSLog(@"2-%@",[NSThread currentThread]);
});
    
dispatch_sync(con_queue, ^{
    NSLog(@"3-%@",[NSThread currentThread]);
});
  • 非主線程下,異步是否新開線程
    dispatch_queue_t ser_queue = dispatch_queue_create("串行", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t con_queue = dispatch_queue_create("並行", DISPATCH_QUEUE_CONCURRENT);

    
    dispatch_async(ser_queue, ^{
        NSLog(@"1-%@",[NSThread currentThread]);
        dispatch_async(ser_queue, ^{
            NSLog(@"1-%@",[NSThread currentThread]);
        });
    });
    
    dispatch_async(ser_queue, ^{
        NSLog(@"2-%@",[NSThread currentThread]);
        dispatch_async(con_queue, ^{
            NSLog(@"2-%@",[NSThread currentThread]);
        });
    });
    
    dispatch_async(con_queue, ^{
        NSLog(@"3-%@",[NSThread currentThread]);
        dispatch_async(con_queue, ^{
            NSLog(@"3-%@",[NSThread currentThread]);
        });
    });
    
    dispatch_async(con_queue, ^{
        NSLog(@"4-%@",[NSThread currentThread]);
        dispatch_async(ser_queue, ^{
            NSLog(@"4-%@",[NSThread currentThread]);
        });
    });

    dispatch_async(ser_queue, ^{
        NSLog(@"5-%@",[NSThread currentThread]);
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"5-%@",[NSThread currentThread]);
        });
    });

    dispatch_async(con_queue, ^{
        NSLog(@"6-%@",[NSThread currentThread]);
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"6-%@",[NSThread currentThread]);
        });
    });
  • 非主線程下,同步是否新開線程
    dispatch_async(ser_queue, ^{
        NSLog(@"1-%@",[NSThread currentThread]);
        dispatch_sync(ser_queue, ^{
            NSLog(@"1-%@",[NSThread currentThread]);
        });
    });
    
    dispatch_async(ser_queue, ^{
        NSLog(@"2-%@",[NSThread currentThread]);
        dispatch_sync(con_queue, ^{
            NSLog(@"2-%@",[NSThread currentThread]);
        });
    });

    dispatch_async(con_queue, ^{
        NSLog(@"3-%@",[NSThread currentThread]);
        dispatch_sync(con_queue, ^{
            NSLog(@"3-%@",[NSThread currentThread]);
        });
    });

    dispatch_async(con_queue, ^{
        NSLog(@"4-%@",[NSThread currentThread]);
        dispatch_sync(ser_queue, ^{
            NSLog(@"4-%@",[NSThread currentThread]);
        });
    });

    dispatch_async(ser_queue, ^{
        NSLog(@"5-%@",[NSThread currentThread]);
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"5-%@",[NSThread currentThread]);
        });
    });
    
    dispatch_async(con_queue, ^{
        NSLog(@"6-%@",[NSThread currentThread]);
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"6-%@",[NSThread currentThread]);
        });
    });

結論:
結果就不貼出來了,還是自己親自測下比較好。看看自己的想法和答案是否一致可是一件很快樂的事情。
基本上覆蓋了所有可能。感覺更像是面向隊列來的,線程的調度是系統自己分配的。

測下來感覺就是回答了兩個問題:

  • async什么時候會新開線程
  • sync什么時候會導致死鎖

我的答案:

  • 主隊列:一定會在主線程
  • 串行隊列:async會開一條線程
  • 並行隊列:async會開多條線程
  • 死鎖:必須是串行隊列,其次提交block所在隊列和把block放進去的隊列是同一個。
  • async不同的隊列,基本上是在不同的線程上。(存疑)
  • 提交block的隊列和block放進去的隊列是同一個,不管串行並行,都在同一個線程上。(存疑)

GCD是神器,還有好多需要學習的地方,推薦幾篇經典的文章:
GCD掃盲篇巧談GCD
GCD進階篇
死鎖,圖文並茂,清晰易懂


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM