GCD的背景和使用中的一些問題

一、多線程背景

Although threads have been around for many years and continue to have their uses, they do not solve the general problem of executing multiple tasks in a scalable way. With threads, the burden of creating a scalable solution rests squarely on the shoulders of you, the developer. You have to decide how many threads to create and adjust that number dynamically as system conditions change. Another problem is that your application assumes most of the costs associated with creating and maintaining any threads it uses.

上述大致說出了直接操縱線程實現多線程的弊端:

開發人員必須根據系統的變化動態調整線程的數量和狀態,即對開發者的負擔重。
應用程序會在創建和維護線程上消耗很多成本,即效率低。
相對的,GCD是一套低層級的C API,通過 GCD,開發者只需要向隊列中添加一段代碼塊(block或C函數指針),而不需要直接和線程打交道。GCD在後端管理着一個線程池,它不僅決定着你的代碼塊將在哪個線程被執行,還根據可用的系統資源對這些線程進行管理。GCD的工作方式,使其擁有很多優點(快、穩、準):

快,更快的內存效率,因爲線程棧不暫存於應用內存。
穩,提供了自動的和全面的線程池管理機制,穩定而便捷。
準,提供了直接並且簡單的調用接口,使用方便,準確。


二、內存和安全

稍微提一下吧,因爲部分人糾結於dispatch的內存問題。
內存

MRC:用dispatch_retain和dispatch_release管理dispatch_object_t內存。
ARC:ARC在編譯時刻自動管理dispatch_object_t內存,使用retain和release會報錯。
安全
dispatch_queue是線程安全的,你可以隨意往裏面添加任務。


三、拾遺

這裏主要提一下GCD的一些坑和線程的一些問題。

1.死鎖

dispatch_sync

// 假設這段代碼執行於主隊列
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t mainQueue = dispatch_get_main_queue();

// 在主隊列添加同步任務
dispatch_sync(mainQueue, ^{
    // 任務
    ...
});

// 在串行隊列添加同步任務 
dispatch_sync(serialQueue, ^{
    // 任務
    ...
    dispatch_sync(serialQueue, ^{
        // 任務
        ...
    });
};

dispatch_apply

// 因爲dispatch_apply會卡住當前線程,內部的dispatch_apply會等待外部,外部的等待內部,所以死鎖。
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_apply(10, queue, ^(size_t) {
    // 任務
    ...
    dispatch_apply(10, queue, ^(size_t) {
        // 任務
        ...
    });
});

dispatch_barrier
dispatch_barrier_sync在串行隊列和全局並行隊列裏面和dispatch_sync同樣的效果,所以需考慮同dispatch_sync一樣的死鎖問題。

2.dispatch_time_t

// dispatch_time_t一般在dispatch_after和dispatch_group_wait等方法裏作爲參數使用。這裏最需要注意的是一些宏的含義。
// NSEC_PER_SEC,每秒有多少納秒。
// USEC_PER_SEC,每秒有多少毫秒。
// NSEC_PER_USEC,每毫秒有多少納秒。
// DISPATCH_TIME_NOW 從現在開始
// DISPATCH_TIME_FOREVE 永久

// time爲1s的寫法
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC);
發佈了26 篇原創文章 · 獲贊 7 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章