Dispatch I/O 本地讀取

1.Dispatch I/O 簡單介紹

  • 在《iOS和OSX多線程和內(nèi)存管理》上看到Dispatch I/O的介紹,介紹了一個簡單應用就是日至API中使用到了這個技術(shù)
  • 日至輸出源碼
  • 想在網(wǎng)上找一些應用的介紹和詳細使用,很可惜沒找到什么有用的,很多都是把書中內(nèi)容拷貝了一遍,實際使用和一些參數(shù)的使用并沒有涉及
  • 文章只是涉及了文件本地讀取,文件的遠程讀取&寫入,會在后續(xù)的文章中更新
    • 應用1 : 串行異步讀取本地文件
    • 應用2 : 并發(fā)異步讀取本地文件
  • 我的BLOG更新,如果有什么錯誤請指導和指正
  • 上一段官方注釋和解析,可能有點難理解,可以根據(jù)具體應用去分析(也因為我的英語水平太爛了)
/*! @header
 * Dispatch I/O provides both stream and random access asynchronous read and write operations on file descriptors. 
 * //同時提供了stream & random 兩種異步文件讀寫操作

 * One or more dispatch I/O channels may be created from a file descriptor as either the DISPATCH_IO_STREAM type or DISPATCH_IO_RANDOM type.
 * // 可同時創(chuàng)建 DISPATCH_IO_STREAM &  DISPATCH_IO_RANDOM 單個或者多個channel

 * Once a channel has been created the application may schedule asynchronous read and write operations.The application may set policies on the dispatch I/O channel to indicate the desired frequency of I/O handlers for long-running operations.
 * // 一旦channel創(chuàng)建,應用會根據(jù)配置項去異步調(diào)度讀寫操作,APP會根據(jù)設置值去多線程文件操作來實現(xiàn)一個較長持續(xù)時間的I/O操作
 *
 * Dispatch I/O also provides a memory management model for I/O buffers that avoids unnecessary copying of data when pipelined between channels. 
 * //Dispatch I/O 也提供一個內(nèi)存管理模型針對I/0 buffer ,以防止不必要的channel之間的拷貝數(shù)據(jù)
 
 * Dispatch I/O monitors the overall memory pressure and I/O access patterns for the application to optimize resource utilization.
 * //Dispatch I/O 監(jiān)控APP 的總內(nèi)存 和I/O訪問模式,以優(yōu)化資源利用率。
 */

2. 串行異步讀取本地文件

  • 使用場景 : 適合文章類的讀取操作(PDF,md,word.txt...),因為串行隊列,所以讀取的文章是順序的,在實際使用更多
  • 示例讀取文件大小 : 1113294 字節(jié)
2.1 代碼
//為了驗證設置單次讀取大小,讀取次數(shù)是否正確
static int serialNumberl = 0;

//異步串行讀取文件
- (void)asyncSerialReadData {
    
    NSString *path = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"md"];
    
    // 見2.2 解析1
     //dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
     
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 見2.2 解析2
    dispatch_io_t chanel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, [path UTF8String], 0, 0, queue, ^(int error) {
        
    });
    
    // 見2.3 解析3
    size_t water = 1024;
    dispatch_io_set_low_water(chanel, water);
    dispatch_io_set_high_water(chanel, water);
    NSMutableData *totalData = [[NSMutableData alloc] init];
    
    //讀取操作
    dispatch_io_read(chanel, 0, SIZE_MAX, queue, ^(bool done, dispatch_data_t  _Nullable data, int error) {
        
        if (error == 0) {
            // 單次讀取大小
            size_t size = dispatch_data_get_size(data);
            if (size > 0 ) {
                [totalData appendData:(NSData*)data]; //拼接數(shù)據(jù)
            }
        }
        
        if (done) {
                // 完整讀寫結(jié)果
            NSString *str = [[NSString alloc] initWithData:totalData encoding:NSUTF8StringEncoding];
            NSLog(@"%@", str);
        }else {
            serialNumberl ++;
            NSLog(@"read not done,第%d次讀取,在%@線程",serialNumberl,[NSThread currentThread]);
        }
        
        
    });
}

2.2 參數(shù)解析

  • 解析1 : 創(chuàng)建隊列

    • 很多文章中都使用了 QOS_CLASS_DEFAULT 這個配置項,我在文中使用默認創(chuàng)建隊列優(yōu)先級參數(shù),我覺得本地讀取使用能夠需求,但是也解釋一下 QOS_CLASS_DEFAULT 這個配置項
    • 個人覺得設計網(wǎng)絡資源的讀取和寫入需要使用QOS_CLASS_DEFAULT,本地讀取沒有必要
     //QOS: QOS(服務質(zhì)量),解決網(wǎng)絡延遲,丟包,阻塞等問題,個人覺得
    
    /*
     * @constant QOS_CLASS_DEFAULT
     * QOS class information is not available. //涉及到使用QOS使用這個參數(shù)無效!!!
     * @discussion Such work is requested to run at a priority below critical user-interactive and user-initiated work, but relatively higher than utility and
    

background tasks. Threads created by pthread_create() without an attribute specifying a QOS class will default to QOS_CLASS_DEFAULT. This QOS class value is not intended to be used as a work classification, it should only be set when propagating or restoring QOS class values provided by the system.
//優(yōu)先級低于 user-interactive配置項,這個QOS類value不涉及具體的工作內(nèi)容,它應該只是傳播或恢復系統(tǒng)提供的QOS類時默認設置。
*/
```

  • 解析2 : 根據(jù)路徑創(chuàng)建I/O Channel
  • 本地讀取使用這個API,可以根據(jù)path讀取
    /*!
     * dispatch_io_create_with_path
     * 
     * 根據(jù)path創(chuàng)建channel
     *
     * param type    The desired type of I/O channel (DISPATCH_IO_STREAM  or DISPATCH_IO_RANDOM) //DISPATCH_IO_STREAM順序連續(xù)(serially)讀取, DISPATCH_IO_RANDOM隨機讀取
    
     * param path    The absolute path to associate with the I/O channel. // 讀取路徑
     * param oflag    The flags to pass to open(2) when opening the file at path. 
     * param mode   
     * param queue    
     * param cleanup_handler   //回調(diào)
     */
    
  • 解析3 : 設置單次讀取大小最大值,最小值
    • 文件總大小1113294,設置單次讀取大小為1024后,總共打印讀取了1088次
    • 根據(jù)具體需求來設置單次讀取大小,但是有什么規(guī)則,我還沒摸索出來,有知道建議的請指導
    • 如果I/O處理操作需要固定大小的中間結(jié)果(既單次讀取或者寫入是固定大小),而不是單次隨機的,則將low & high 值設置為相同的大小
    • 如果不需要局部讀寫結(jié)果,則將low mask 設置為SIZE_MAX
```

dispatch_io_set_low_water // 單次讀取mark的字節(jié)大小

* If an I/O handler requires intermediate results of fixed size, set both the low and and the high water mark to that size //如果I/O處理程序需要固定大小的中間結(jié)果,而不是單次隨機的,則將low & high 值設置為相同的 *
  • The default value for the low water mark is unspecified, but must be assumed to be such that intermediate handler invocations may occur.
  • If I/O handler invocations with partial results are not desired, set the low water mark to SIZE_MAX. //如果不需要具有部分結(jié)果的,則將low mask 設置為SIZE_MAX。
    
    
    

3. 并發(fā)異步讀取本地文件

  • 并發(fā)讀取有個實際問題:如果是文章類的,由于并發(fā)讀取,所以拼接后順序會錯亂,若想要正確順序,還需要讀取時有加鎖或者別的操作
  • 并發(fā)讀取速度遠大于串行讀取速度
  • 代碼:需要重新雕琢修改一下
3.1 代碼
static int concurrentNumber = 0;

- (void)asyncConcurrentReadData {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"md"];
    
    dispatch_queue_t queue = dispatch_queue_create("readDataQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();

    
    //見3.2 解析1
    dispatch_fd_t fd = open(path.UTF8String, O_RDONLY);
   
    dispatch_io_t io = dispatch_io_create(DISPATCH_IO_RANDOM, fd, queue, ^(int error) {
        close(fd);
    });
    
    
    long long fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil].fileSize;
    size_t offset = 128 * 128;
    
     NSMutableData *totalData = [[NSMutableData alloc] initWithLength:fileSize];
   
    for (off_t currentSize = 0; currentSize <= fileSize; currentSize += offset) {
        
        dispatch_group_enter(group);
        
        //dispatch_io_read默認異步
        dispatch_io_read(io, currentSize, offset, queue, ^(bool done, dispatch_data_t  _Nullable data, int error) {
            
            if (error == 0) {
                size_t size = dispatch_data_get_size(data);
                if (size > 0) {
                    dispatch_semaphore_wait(weakSelf.semaphore, DISPATCH_TIME_FOREVER);
                    [totalData appendData:(NSData*)data];
                    dispatch_semaphore_signal(weakSelf.semaphore);  
                }
                
            }
            
            if (done) {
                dispatch_group_leave(group);
            }else {
            NSLog(@"read not done,第%d次讀取,在%@線程",concurrentNumberl,[NSThread currentThread]);
            }
            
        });
        
    }
    
    dispatch_group_notify(group, queue, ^{
        NSString *str = [[NSString alloc] initWithData:totalData encoding:NSUTF8StringEncoding];
        NSLog(@"%@", str);
    });
    
}

3.2 解析
  • 解析1 : dispatch_fd _t,文件描述類型

    typedef int dispatch_fd_t;
    * Native file descriptor type for the platform.//平臺原生文件描述類型有不同模式
    #define O_RDONLY    0x0000      // 只讀 , open for reading only 
    #define O_WRONLY    0x0001      // 只寫, open for writing only 
    #define O_RDWR      0x0002      //讀寫, open for reading and writing
    #define O_ACCMODE   0x0003  //all mode 
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,621評論 1 32
  • iOS多線程編程 基本知識 1. 進程(process) 進程是指在系統(tǒng)中正在運行的一個應用程序,就是一段程序的執(zhí)...
    陵無山閱讀 6,335評論 1 14
  • Dispatch Sources 現(xiàn)代系統(tǒng)通常提供異步接口,允許應用向系統(tǒng)提交請求,然后在系統(tǒng)處理請求時應用可以繼...
    好雨知時節(jié)浩宇閱讀 3,908評論 2 5
  • OC語言基礎 1.類與對象 類方法 OC的類方法只有2種:靜態(tài)方法和實例方法兩種 在OC中,只要方法聲明在@int...
    奇異果好補閱讀 4,517評論 0 11
  • 1.NSTimer不準時的原因:(1).RunLoop循環(huán)處理時間,每次循環(huán)是固定時間,只有在這段時間才會去查看N...
    稻春閱讀 1,355評論 0 3

友情鏈接更多精彩內(nèi)容