偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

GCD介紹(三):Dispatch Sources

移動開發(fā) iOS
本文為大家講述怎樣使用GCD的dispatch source功能來監(jiān)視文件描述符、計時器、聯(lián)結(jié)的用戶事件以及其他類似的行為。由于dispatch source完全與dispatch queue相集成,所以你可以使用任意的dispatch queue。你可以將一個dispatch source的句柄在主線程中執(zhí)行、在全局隊列中并發(fā)執(zhí)行、或者在用戶隊列中串行執(zhí)行(執(zhí)行時會將程序的其他模塊的運算考慮在內(nèi))。

[[77411]]

何為Dispatch Sources

簡單來說,dispatch source是一個監(jiān)視某些類型事件的對象。當這些事件發(fā)生時,它自動將一個block放入一個dispatch queue的執(zhí)行例程中。

說的貌似有點不清不楚。我們到底討論哪些事件類型?

下面是GCD 10.6.0版本支持的事件:

  1. Mach port send right state changes.
  2. Mach port receive right state changes.
  3. External process state change.
  4. File descriptor ready for read.
  5. File descriptor ready for write.
  6. Filesystem node event.
  7. POSIX signal.
  8. Custom timer.
  9. Custom event.

這是一堆很有用的東西,它支持所有kqueue所支持的事件(kqueue是什么?見http://en.wikipedia.org/wiki/Kqueue)以及mach(mach是什么?見http://en.wikipedia.org/wiki/Mach_(kernel))端口、內(nèi)建計時器支持(這樣我們就不用使用超時參數(shù)來創(chuàng)建自己的計時器)和用戶事件。

用戶事件

這些事件里面多數(shù)都可以從名字中看出含義,但是你可能想知道啥叫用戶事件。簡單地說,這種事件是由你調(diào)用dispatch_source_merge_data函數(shù)來向自己發(fā)出的信號。

這個名字對于一個發(fā)出事件信號的函數(shù)來說,太怪異了。這個名字的來由是GCD會在事件句柄被執(zhí)行之前自動將多個事件進行聯(lián)結(jié)。你可以將數(shù)據(jù)“拼接”至dispatch source中任意次,并且如果dispatch queue在這期間繁忙的話,GCD只會調(diào)用該句柄一次(不要覺得這樣會有問題,看完下面的內(nèi)容你就明白了)。

用戶事件有兩種: DISPATCH_SOURCE_TYPE_DATA_ADD 和 DISPATCH_SOURCE_TYPE_DATA_OR.用戶事件源有個 unsigned long data屬性,我們將一個 unsigned long傳入 dispatch_source_merge_data。當使用 _ADD版本時,事件在聯(lián)結(jié)時會把這些數(shù)字相加。當使用 _OR版本時,事件在聯(lián)結(jié)時會把這些數(shù)字邏輯與運算。當事件句柄執(zhí)行時,我們可以使用dispatch_source_get_data函數(shù)訪問當前值,然后這個值會被重置為0。

讓我假設(shè)一種情況。假設(shè)一些異步執(zhí)行的代碼會更新一個進度條。因為主線程只不過是GCD的另一個dispatch queue而已,所以我們可以將GUI更新工作push到主線程中。然而,這些事件可能會有一大堆,我們不想對GUI進行頻繁而累贅的更新,理想的情況是當主線程繁忙時將所有的改變聯(lián)結(jié)起來。

用dispatch source就完美了,使用DISPATCH_SOURCE_TYPE_DATA_ADD,我們可以將工作拼接起來,然后主線程可以知道從上一次處理完事件到現(xiàn)在一共發(fā)生了多少改變,然后將這一整段改變一次更新至進度條。

啥也不說了,上代碼:

  1. dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue()); 
  2. dispatch_source_set_event_handler(source, ^{ 
  3.     [progressIndicator incrementBy:dispatch_source_get_data(source)]; 
  4. }); 
  5. dispatch_resume(source); 
  6.  
  7. dispatch_apply([array count], globalQueue, ^(size_t index) { 
  8.     // do some work on data at index 
  9.     dispatch_source_merge_data(source, 1); 
  10. }); 

(對于這段代碼,我很想說點什么,我第一次用dispatch source時,我糾結(jié)了很久很久,真讓人蛋疼:Dispatch source啟動時默認狀態(tài)是掛起的,我們創(chuàng)建完畢之后得主動恢復(fù),否則事件不會被傳遞,也不會被執(zhí)行

假設(shè)你已經(jīng)將進度條的min/max值設(shè)置好了,那么這段代碼就完美了。數(shù)據(jù)會被并發(fā)處理。當每一段數(shù)據(jù)完成后,會通知dispatch source并將dispatch source data加1,這樣我們就認為一個單元的工作完成了。事件句柄根據(jù)已完成的工作單元來更新進度條。若主線程比較空閑并且這些工作單元進行的比較慢,那么事件句柄會在每個工作單元完成的時候被調(diào)用,實時更新。如果主線程忙于其他工作,或者工作單元完成速度很快,那么完成事件會被聯(lián)結(jié)起來,導(dǎo)致進度條只在主線程變得可用時才被更新,并且一次將積累的改變更新至GUI。

現(xiàn)在你可能會想,聽起來倒是不錯,但是要是我不想讓事件被聯(lián)結(jié)呢?有時候你可能想讓每一次信號都會引起響應(yīng),什么后臺的智能玩意兒統(tǒng)統(tǒng)不要。啊。。其實很簡單的,別把自己繞進去了。如果你想讓每一個信號都得到響應(yīng),那使用dispatch_async函數(shù)不就行了。實際上,使用的dispatch source而不使用dispatch_async的唯一原因就是利用聯(lián)結(jié)的優(yōu)勢。

內(nèi)建事件

上面就是怎樣使用用戶事件,那么內(nèi)建事件呢?看看下面這個例子,用GCD讀取標準輸入:

  1.     dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
  2.     dispatch_source_t stdinSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, 
  3.                                                            STDIN_FILENO, 
  4.                                                            0, 
  5. globalQueue); 
  6.     dispatch_source_set_event_handler(stdinSource, ^{ 
  7.         char buf[1024]; 
  8.         int len = read(STDIN_FILENO, buf, sizeof(buf)); 
  9.         if(len > 0) 
  10.             NSLog(@"Got data from stdin: %.*s", len, buf); 
  11.     }); 
  12.     dispatch_resume(stdinSource); 

簡單的要死!因為我們使用的是全局隊列,句柄自動在后臺執(zhí)行,與程序的其他部分并行,這意味著對這種情況的提速:事件進入程序時,程序正在處理其他事務(wù)。

這是標準的UNIX方式來處理事務(wù)的好處,不用去寫loop。如果使用經(jīng)典的 read調(diào)用,我們還得萬分留神,因為返回的數(shù)據(jù)可能比請求的少,還得忍受無厘頭的“errors”,比如 EINTR (系統(tǒng)調(diào)用中斷)。使用GCD,我們啥都不用管,就從這些蛋疼的情況里解脫了。如果我們在文件描述符中留下了未讀取的數(shù)據(jù),GCD會再次調(diào)用我們的句柄。

對于標準輸入,這沒什么問題,但是對于其他文件描述符,我們必須考慮在完成讀寫之后怎樣清除描述符。對于dispatch source還處于活躍狀態(tài)時,我們決不能關(guān)閉描述符。如果另一個文件描述符被創(chuàng)建了(可能是另一個線程創(chuàng)建的)并且新的描述符剛好被分配了相同的數(shù)字,那么你的dispatch source可能會在不應(yīng)該的時候突然進入讀寫狀態(tài)。de這個bug可不是什么好玩的事兒。

適當?shù)那宄绞绞鞘褂?nbsp;dispatch_source_set_cancel_handler,并傳入一個block來關(guān)閉文件描述符。然后我們使用 dispatch_source_cancel來取消dispatch source,使得句柄被調(diào)用,然后文件描述符被關(guān)閉。

使用其他dispatch source類型也差不多??偟膩碚f,你提供一個source(mach port、文件描述符、進程ID等等)的區(qū)分符來作為diapatch source的句柄。mask參數(shù)通常不會被使用,但是對于 DISPATCH_SOURCE_TYPE_PROC 來說mask指的是我們想要接受哪一種進程事件。然后我們提供一個句柄,然后恢復(fù)這個source(前面我加粗字體所說的,得先恢復(fù)),搞定。dispatch source也提供一個特定于source的data,我們使用 dispatch_source_get_data函數(shù)來訪問它。例如,文件描述符會給出大致可用的字節(jié)數(shù)。進程source會給出上次調(diào)用之后發(fā)生的事件的mask。具體每種source給出的data的含義,看man page吧。

計時器

計時器事件稍有不同。它們不使用handle/mask參數(shù),計時器事件使用另外一個函數(shù) dispatch_source_set_timer 來配置計時器。這個函數(shù)使用三個參數(shù)來控制計時器觸發(fā):

start參數(shù)控制計時器第一次觸發(fā)的時刻。參數(shù)類型是 dispatch_time_t,這是一個opaque類型,我們不能直接操作它。我們得需要 dispatch_time 和  dispatch_walltime 函數(shù)來創(chuàng)建它們。另外,常量  DISPATCH_TIME_NOW 和 DISPATCH_TIME_FOREVER 通常很有用。

interval參數(shù)沒什么好解釋的。

leeway參數(shù)比較有意思。這個參數(shù)告訴系統(tǒng)我們需要計時器觸發(fā)的精準程度。所有的計時器都不會保證100%精準,這個參數(shù)用來告訴系統(tǒng)你希望系統(tǒng)保證精準的努力程度。如果你希望一個計時器沒五秒觸發(fā)一次,并且越準越好,那么你傳遞0為參數(shù)。另外,如果是一個周期性任務(wù),比如檢查email,那么你會希望每十分鐘檢查一次,但是不用那么精準。所以你可以傳入60,告訴系統(tǒng)60秒的誤差是可接受的。

這樣有什么意義呢?簡單來說,就是降低資源消耗。如果系統(tǒng)可以讓cpu休息足夠長的時間,并在每次醒來的時候執(zhí)行一個任務(wù)集合,而不是不斷的醒來睡去以執(zhí)行任務(wù),那么系統(tǒng)會更高效。如果傳入一個比較大的leeway給你的計時器,意味著你允許系統(tǒng)拖延你的計時器來將計時器任務(wù)與其他任務(wù)聯(lián)合起來一起執(zhí)行。

總結(jié)

現(xiàn)在你知道怎樣使用GCD的dispatch source功能來監(jiān)視文件描述符、計時器、聯(lián)結(jié)的用戶事件以及其他類似的行為。由于dispatch source完全與dispatch queue相集成,所以你可以使用任意的dispatch queue。你可以將一個dispatch source的句柄在主線程中執(zhí)行、在全局隊列中并發(fā)執(zhí)行、或者在用戶隊列中串行執(zhí)行(執(zhí)行時會將程序的其他模塊的運算考慮在內(nèi))。

下一篇我會討論如何對dispatch queue進行掛起、恢復(fù)、重定目標操作;如何使用dispatch semaphore;如何使用GCD的一次性初始化功能。

責任編輯:閆佳明 來源: dreamingwish
相關(guān)推薦

2013-07-15 15:51:32

iOS多線程GCD基本概念Dispatch Qu

2013-07-15 16:28:15

iOS多線程GCD介紹Dispatch Qu

2013-07-15 16:00:59

2015-06-26 09:29:12

Grand Centr

2013-07-15 15:23:03

iOS多線程GCD

2023-02-03 14:41:03

地址翻譯模式loongarch

2013-07-15 16:55:54

iOS多線程GCD實戰(zhàn)資源競爭

2011-04-26 11:03:36

三星打印機

2010-03-17 17:16:46

Fedora 常用軟件

2012-09-20 10:50:34

IBMdw

2011-08-15 11:13:06

IOS開發(fā)并發(fā)Dispatch Qu

2020-12-18 10:04:52

API漏洞應(yīng)用程序編程接口

2010-04-19 09:31:44

KDE

2010-03-05 11:18:52

Linux shell

2010-04-20 12:00:01

負載均衡技術(shù)

2010-04-26 17:15:13

Oracle優(yōu)化器

2011-07-19 10:26:49

Active Dire回收站

2012-03-15 16:20:35

TizenIntel三星

2009-11-10 12:48:17

VB.NET三維模型

2011-07-21 17:45:02

java
點贊
收藏

51CTO技術(shù)棧公眾號