
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