iOS開發-多線程編程

来源:https://www.cnblogs.com/jianqiu/p/18316118
-Advertisement-
Play Games

OC中常用的多線程編程技術: 1. NSThread NSThread是Objective-C中最基本的線程抽象,它允許程式員直接管理線程的生命周期。 NSThread *myThread = [[NSThread alloc] initWithTarget:self selector:@selec ...


OC中常用的多線程編程技術:

1. NSThread

NSThread是Objective-C中最基本的線程抽象,它允許程式員直接管理線程的生命周期。

NSThread *myThread = [[NSThread alloc] initWithTarget:self selector:@selector(myThreadMainMethod:) object:nil];
[myThread start];

使用NSThread時,需要自己管理線程的生命周期,包括創建、啟動和銷毀線程。這種方法給了開發者很大的控制權,但也增加了複雜性,因為需要手動處理線程同步和線程安全問題。

2. Grand Central Dispatch (GCD)

GCD是一個強大的基於C語言的API,它提供了一個併發執行任務的低級別方式。GCD使用任務隊列和線程池來優化線程的使用。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
    // 非同步執行的任務
});

GCD是推薦的多線程編程方法之一,因為它的性能很好,而且簡化了併發編程的複雜性(下一節詳細介紹)。

3. Operation Queues

NSOperationNSOperationQueue提供了一個面向對象的方式來執行併發操作。NSOperation是一個抽象類,可以通過繼承它來定義具體的操作。

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(myTaskMethod) object:nil];
[queue addOperation:operation];

NSOperationQueue可以管理多個NSOperation對象,它支持設置最大併發操作數和依賴關係。NSOperation比GCD更高級,它支持取消操作、設置操作依賴和觀察操作狀態。

4. Perform Selector Methods

Objective-C提供了performSelector:onThread:等方法來在指定的線程上執行方法。

[self performSelector:@selector(myTaskMethod) onThread:myThread withObject:nil waitUntilDone:NO];

這些方法簡單易用,但它們不提供GCD和NSOperation的強大功能。

5. POSIX Threads (pthreads)

POSIX線程是一套跨平臺的線程相關的API,Objective-C可以直接使用這些API,因為它是C語言的超集。

#include <pthread.h>

void *myThreadFunction(void *context) {
    // 線程執行的代碼
    return NULL;
}

pthread_t thread;
pthread_create(&thread, NULL, myThreadFunction, NULL);

pthreads提供了很大的控制力,但它是一個低級別的API,通常不推薦在OC中使用,除非需要與C庫交互或有特殊的線程管理需求。

GCD的詳細介紹

Grand Central Dispatch (GCD) 是 Apple 開發的一個強大的多核編程解決方案,它提供了一種簡單且高效的方式來管理併發任務。GCD 使用任務(blocks of code)和隊列(queues)的概念來執行工作。它是基於 C 語言實現的,可以在 Objective-C 和 Swift 中使用。

核心概念

任務

任務是指要執行的工作,通常是以 block 的形式提供。在 Objective-C 中,一個任務可以是一個 block 或者一個函數。

隊列

隊列是一種特殊的數據結構,用於按順序存儲任務。GCD 提供了兩種類型的隊列:

  • 串列隊列(Serial Queue):一次只執行一個任務。隊列中的任務按照添加的順序依次執行。在內部實現了一種機制,確保隊列中的任務一次只能執行一個,並且按照它們被添加到隊列中的順序來執行。這是通過隊列管理和任務調度來實現的。

當將一個任務提交到串列隊列時,這裡是大致的工作流程:

  1. 任務排隊:任務被添加到隊列的末尾。如果隊列是空的,它會成為隊列中的第一個任務。

  2. 任務執行:隊列中的第一個任務(隊頭)被取出來執行。在這個任務執行期間,隊列不會執行或者開始執行任何其他任務。

  3. 任務完成:一旦當前執行的任務完成,它會從隊列中移除。

  4. 下一個任務:隊列中的下一個任務(現在是隊頭)開始執行。

  5. 重覆過程:這個過程會一直重覆,直到隊列中的所有任務都被執行完畢。

串列隊列的關鍵特性是互斥執行,這意味著在任何給定時間點,隊列中只有一個任務在執行。這種互斥是由GCD的底層調度機制保證的,它確保了即使在多核處理器上,串列隊列上的任務也不會並行執行。

這種執行方式使得串列隊列成為了同步執行任務的理想選擇,特別是需要按順序執行一系列任務,而這些任務又不能同時執行時(例如,當任務需要按特定順序訪問或修改共用資源時)。因此理論上一個線程就足夠了。這是串列隊列如何保證任務順序執行和互斥的關鍵。當一個任務在串列隊列中開始執行時,它會持續運行直到完成,然後隊列才會執行下一個任務。這個過程不需要同時有多個線程參與,因為不會有並行執行的情況。然而,實際上,由於GCD的工作原理,它可能會在內部使用多個線程來管理多個串列隊列。GCD使用線程池來優化線程的使用,這意味著它會根據需要動態地為隊列分配和回收線程。但對於任何單一的串列隊列來說,你可以認為它在任何時候都只在一個線程上執行任務。這種設計使得串列隊列成為管理共用資源和避免併發問題的理想工具,因為它簡化了同步和線程安全的需求。同時,它也減少了上下文切換的開銷,因為任務是在單個線程上連續執行的。

  • 並行隊列(Concurrent Queue):可以同時執行多個任務。任務可以併發執行,但完成的順序可能會不同。

系統隊列

GCD 提供了幾種不同類型的系統隊列:

  • 主隊列(Main Queue):串列隊列,用於在主線程上執行任務,通常用於更新 UI。
  • 全局隊列(Global Queues):並行隊列,有四個不同優先順序的全局隊列:高、預設、低和後臺。

Grand Central Dispatch (GCD) 提供了幾種不同類型的系統隊列,這些隊列是預先創建好的,可以直接使用。它們分為兩大類:主隊列(Main Queue)和全局隊列(Global Queues)。

主隊列(Main Queue)
  • 主隊列是一個特殊的串列隊列,它在應用程式的主線程上執行任務。因為主線程通常用於更新UI,所以所有的UI更新都應該在主隊列上執行,以確保UI的平滑和響應性。
  • 使用dispatch_get_main_queue()函數可以獲取主隊列。
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{
    // 在主線程上更新UI
});
全局隊列(Global Queues)
  • 全局隊列是並行隊列,它們在後臺執行任務,不會阻塞主線程。全局隊列有四個不同的優先順序:高(high)、預設(default)、低(low)和後臺(background)。這些優先順序對應於系統為任務分配的相對重要性。
  • 使用dispatch_get_global_queue()函數可以獲取全局隊列,需要指定優先順序和一個保留用的標誌位(目前應該傳遞0)。
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(globalQueue, ^{
    // 在後臺執行耗時任務
});

全局隊列的優先順序:

  • 高優先順序DISPATCH_QUEUE_PRIORITY_HIGH):用於需要立即執行的任務,但不應該阻塞主線程。
  • 預設優先順序DISPATCH_QUEUE_PRIORITY_DEFAULT):用於大多數任務,如果沒有特殊的優先順序要求,應該使用這個優先順序。
  • 低優先順序DISPATCH_QUEUE_PRIORITY_LOW):用於不急迫的任務,可以等待其他更重要的任務完成後再執行。
  • 後臺優先順序DISPATCH_QUEUE_PRIORITY_BACKGROUND):用於那些用戶不太可能立即註意到的任務,如預取數據、維護或清理工作。
    註意以下事項:
  • 儘管全局隊列是並行隊列,但是任務的啟動順序仍然是按照它們被添加到隊列的順序。
  • 全局隊列不保證任務完成的順序,任務可以併發執行。
  • 主隊列保證任務按照添加的順序一個接一個地執行。
  • 在主隊列上同步執行任務會導致死鎖,因為主隊列等待同步任務完成,而同步任務又在等待主隊列可用,從而形成了相互等待的情況。

自定義隊列

除了系統隊列,GCD還允許創建自定義隊列。自定義隊列可以是串列的也可以是並行的。

  • 創建串列隊列:
dispatch_queue_t serialQueue = dispatch_queue_create("com.example.mySerialQueue", DISPATCH_QUEUE_SERIAL);
  • 創建並行隊列:
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.example.myConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);

使用 GCD

非同步執行

使用 dispatch_async 函數可以非同步地將任務提交到隊列中。這意味著它不會等待任務完成,而是立即返回。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
    // 執行耗時的任務
});

同步執行

使用 dispatch_sync 函數可以同步地將任務提交到隊列中。這會阻塞當前線程,直到任務執行完成。

dispatch_sync(queue, ^{
    // 執行任務
});

延遲執行

使用 dispatch_after 函數可以在指定的時間後非同步執行任務。

double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^{
    // 2秒後執行的任務
});

一次性執行

使用 dispatch_once 函數可以確保代碼塊只被執行一次,常用於創建單例。

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // 只執行一次的代碼
});

隊列組

dispatch_group 允許多個任務作為一個組來提交,併在組中的所有任務完成時得到通知。

dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
    // 任務1
});
dispatch_group_async(group, queue, ^{
    // 任務2
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    // 所有任務完成後執行
});

信號量

dispatch_semaphore 用於控制訪問資源的線程數量,可以用來實現線程同步。

dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
dispatch_async(queue, ^{
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    // 訪問受限資源
    dispatch_semaphore_signal(semaphore);
});

註意事項

  • 不要在串列隊列上同步地執行任務,這可能會導致死鎖。
  • 儘量避免在主隊列上同步執行耗時任務,這會阻塞 UI 更新。
  • 使用 GCD 時,要註意記憶體管理,特別是在 block 中捕獲外部變數時。

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

-Advertisement-
Play Games
更多相關文章
  • 引言 隨著雲計算技術的發展,Amazon Web Services (AWS) 作為一個開放的平臺,一直在幫助開發者更好的在雲上構建和使用開源軟體,同時也與開源社區緊密合作,推動開源項目的發展。 本文主要探討2024年值得關註的一些開源軟體及其在AWS上的應用情況,希望能夠給大家參考使用! 2024 ...
  • 本文分享自天翼雲開發者社區《快照技術對比學習》,作者:z****n 1.快照的分類 根據 SNIA 的定義, 快照有全量快照 (full snapshot) 和增量快照 (incremental snapshot) 兩種類型。 2.全量快照 克隆(Clone): 與備份操作類似,克隆技術是一種數據復 ...
  • Zabbix監控 MS SqlServer2019 環境: Zabbix 7.0 LTS, sqlserver 2019 在mssql server的伺服器上安裝好agent2和插件: zabbix_agent2_plugins-7.0.0-windows-amd64.msi, 其中有mssql的必 ...
  • 前言 Oracle公司(甲骨文)是全球最大的信息管理軟體及服務供應商,成立於1977年,總部位於美國加州Redwood shore,面向全球開放oracle認證。 Oracle開發的關係資料庫產品因性能卓越而聞名,Oracle資料庫產品為財富排行榜上的前1000家公司所採用,許多大型網站也選用了Or ...
  • 一、問題發現 在一次數據遷移中,用到了INSERT INTO t1 SELECT * FROM t2這樣的 SQL 用來搬遷大表,為了提高插入效率關閉了Binlog,考慮用多線程來插入提高速度。表的類型信息和插入效率如下所示。 測試環境: Linux node-76-11 4.19.90-17.ky ...
  • 本文分享自華為雲社區《GaussDB(for MySQL)創新特性:靈活多維的二級分區表策略》,作者:GaussDB 資料庫。 背景介紹 分區表及二級分區表的功能,可以讓資料庫更加有效地管理和查詢大規模數據,傳統商業資料庫具備該能力。MySQL支持分區表,與傳統商業資料庫相比,MySQL對二級分區表 ...
  • 引言 隨著雲計算技術的發展,Amazon Web Services (AWS) 作為一個開放的平臺,一直在幫助開發者更好的在雲上構建和使用開源軟體,同時也與開源社區緊密合作,推動開源項目的發展。 本文主要探討2024年值得關註的一些開源軟體及其在AWS上的應用情況,希望能夠給大家參考使用! 2024 ...
  • 指標管理體系是一個結構化、系統化的方法論,旨在通過一系列精心設計的指標來衡量和指導組織的運營、決策和戰略實施過程。包括戰略對齊與目標設定、指標體系設計、管理流程標準化與自動化、監控與評估等多個核心環節。 本文聚焦於指標管理流程的標準化與自動化實踐,藉助袋鼠雲提供的專業指標管理平臺,將指標管理流程精煉 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...