ink*_*002 6 queue grand-central-dispatch ios serial-processing
我有一个方法,有时可以在我的代码中调用.下面是一个非常基本的示例,因为代码处理iphone照片库中的图像和文件,并在完成该方法时标记它们已经处理过.
@property (nonatomic, assign) dispatch_queue_t serialQueue;
....
-(void)processImages
{
dispatch_async(self.serialQueue, ^{
//block to process images
NSLog(@"In processImages");
....
NSLog(@"Done with processImages");
});
}
Run Code Online (Sandbox Code Playgroud)
我认为每次调用此方法时我都会得到以下输出..."在processImages""使用processImages完成""在processImages""完成了processImages"等...
但我总是得到
"在processImages""在processImages""完成与processImages""完成与processImages"等...
我以为串口队列会等到第一个块完成,然后开始.对我来说,似乎它正在启动方法,然后它再次被调用并在第一个调用完成之前启动,创建通常不会被处理的图像的重复,因为如果它真的按顺序执行,则该方法将知道它们已经处理完毕.也许我对串行队列的理解并不具体.有什么输入?谢谢.
编辑:更多上下文,这是块中发生的事情...这可能导致问题???
@property (nonatomic, assign) dispatch_queue_t serialQueue;
....
-(void)processImages
{
dispatch_async(self.serialQueue, ^{
//library is a reference to ALAssetsLibrary object
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop)
{
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop)
{
....
//Process the photos here
}];
failureBlock:^(NSError *error) { NSLog(@"Error loading images from library");
}];
});
}
-(id)init
{
self = [super init];
if(self)
{
_serialQueue = dispatch_queue_create("com.image.queue",NULL);
}
return self;
}
Run Code Online (Sandbox Code Playgroud)
这个对象只创建一次,据我所知,永远不能再根据我的代码再次创建...我会运行测试以确保.
更新2:我认为发生了什么,如果您同意/不同意,请对此发表评论....
显然我的主要问题是,似乎这个代码块正在同时执行,创建重复的条目(导入相同的照片两次),如果它是串行运行通常不会这样做.处理照片时,会对其应用"脏"位,以确保下次调用该方法时它会跳过此图像,但这不会发生,并且某些图像会被处理两次.这可能是因为我使用enumerategroupswithtypes枚举第二个队列中的对象:在该serialQueue中?
虽然由于enumerategroups可能仍在运行,但是队列可能已完成,因为它在枚举组完成工作之前到达块的末尾,所以processImages并没有真正完成.这对我来说似乎有可能吗?
串行队列绝对会串行执行。但是,不能保证它们在同一线程上执行。
假设您使用相同的串行队列,问题是 NSLog 不能保证在从不同线程同时调用时以正确的顺序输出结果。
这是一个例子:
5. 之后,NSLog 不一定知道要打印哪个,3. 或 4。
如果您绝对需要按时间排序的日志记录,则需要一个专用的日志记录队列。在实践中,我只使用主队列没有问题:
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"whatever");
});
Run Code Online (Sandbox Code Playgroud)
如果所有的 NSlog 调用都在同一个队列中,你就不应该有这个问题。
如果问题是“串行队列可以异步执行任务吗?” 那么答案是否定的。如果您认为可以,您应该确保所有任务确实在同一个队列上执行。您可以在块中添加以下行并比较输出:
dispatch_async(self.serialQueue, ^{
NSLog(@"current queue:%p current thread:%@",dispatch_get_current_queue(),[NSThread currentThread]);
Run Code Online (Sandbox Code Playgroud)
确保您在队列上执行的块中写入 NSLog,而不是在 enumerateGroupsWithTypes:usingBlock:failureBlock 中:您也可以尝试像这样创建队列
dispatch_queue_create("label", DISPATCH_QUEUE_SERIAL);
Run Code Online (Sandbox Code Playgroud)
但我认为这不会改变任何事情
编辑:顺便说一下,方法
enumerateGroupsWithTypes:usingBlock:failureBlock:
Run Code Online (Sandbox Code Playgroud)
是异步的,为什么要在另一个队列上调用呢?
更新2:我可以建议这样的事情:
dispatch_async(queue, ^{
NSLog(@"queue");
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER, *pmutex = &mutex;
pthread_mutex_lock(pmutex);
ALAssetsLibraryGroupsEnumerationResultsBlock listGroupBlock = ^(ALAssetsGroup *group, BOOL *stop) {
NSLog(@"block");
if (group) {
[groups addObject:group];
} else {
[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
dispatch_async(dispatch_get_current_queue(), ^{
pthread_mutex_unlock(pmutex);
});
}
NSLog(@"block end");
};
[assetsLibrary enumerateGroupsWithTypes:groupTypes usingBlock:listGroupBlock failureBlock:failureBlock];
pthread_mutex_lock(pmutex);
pthread_mutex_unlock(pmutex);
pthread_mutex_destroy(pmutex);
NSLog(@"queue end");
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4400 次 |
| 最近记录: |