Mse*_*enb 5 iphone concurrency multithreading grand-central-dispatch ios
所以我将一系列图像发布到我的服务器上.我想使用GCD异步发布数组,但我也想让这个发生同步的方法,以便我可以传回一个响应对象.但是,dispatch_group_wait方法似乎立即返回(而不是等待我的块完成).这是一个问题因为我在块中使用了一个块吗?
NSArray *keys = [images allKeys];
__block NSMutableDictionary *responses = [NSMutableDictionary dictionaryWithCapacity:[images count]];
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < [keys count]; i++) {
__block NSString *key = [keys objectAtIndex:i];
dispatch_group_async(group, queue, ^{
[self postImage:[images objectForKey:key] completionHandler:^(ServerResponse *response){
@synchronized(responses){
if ([response succeeded]) {
NSString *value = [[response data] objectForKey:@"image_token"];
[responses setObject:value forKey:key];
NSLog(@"inside success %@",responses);
} else {
NSString *error = response.displayableError;
if (!error) {
error = @"Sorry something went wrong, please try again later.";
}
[responses setObject:error forKey:@"error"];
[responses setObject:response forKey:@"response"];
}
}
}];
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);
Run Code Online (Sandbox Code Playgroud)
我想简单地等待所有[self postImage]方法从服务器回调并修改响应字典.
乔纳森的信号量示例是目标.但是,我提到使用条件变量作为替代,所以我想我至少会发布一个例子.一般来说,CV可用于等待除N工人以外的更一般条件.
请注意,条件变量有它们的位置(虽然不一定在这里),通常最好在需要锁定以改变共享状态时,然后其他线程可以等待特定条件.
NSUInteger numKeys = [keys count];
NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:numKeys];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (NSUInteger i = 0; i < numKeys; i++) {
__block NSString *key = [keys objectAtIndex:i];
dispatch_async(queue, ^{
[self postImage:[images objectForKey:key] completionHandler:^(ServerResponse *response){
// Basically, nothing more than a obtaining a lock
// Use this as your synchronization primitive to serialize access
// to the condition variable and also can double as primitive to replace
// @synchronize -- if you feel that is still necessary
[conditionLock lock];
...;
// When unlocking, decrement the condition counter
[conditionLock unlockWithCondition:[conditionLock condition]-1];
}];
});
}
// This call will get the lock when the condition variable is equal to 0
[conditionLock lockWhenCondition:0];
// You have mutex access to the shared stuff... but you are the only one
// running, so can just immediately release...
[conditionLock unlock];
Run Code Online (Sandbox Code Playgroud)
在没有看到代码的情况下-postImage:completionHandler:,很难说事情的安排在哪里,但我假设他们打电话给iOS提供的东西.如果是这样,则块内的处理程序块将异步调度到全局队列,然后iOS提供的函数或方法立即返回.就您的调度组而言,工作几乎是立即完成的.
没有简单的方法可以让小组等待在拨打电话时尚未安排的工作dispatch_group_wait().但是,我们可以添加一个名为信号量的低级thingamajigger ,它确保我们的操作按正确的顺序完成,并将其安排在内部(异步)块的范围之外.
NSUInteger numKeys = [keys count];
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (NSUInteger i = 0; i < numKeys; i++) {
__block NSString *key = [keys objectAtIndex:i];
dispatch_group_async(group, queue, ^{
// We create a semaphore for each block here. More on that in a moment.
// The initial count of the semaphore is 1, meaning that a signal must happen
// before a wait will return.
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
[self postImage:[images objectForKey:key] completionHandler:^(ServerResponse *response){
...
// This instructs one caller (i.e. the outer block) waiting on this semaphore to resume.
dispatch_semaphore_signal(sem);
}];
// This instructs the block to wait until signalled (i.e. at the end of the inner block.)
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
// Done with the semaphore. Nothing special here.
dispatch_release(sem);
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
// Now all the tasks should have completed.
dispatch_release(group);
Run Code Online (Sandbox Code Playgroud)
这里有一个问题.信号量是一种内核资源.如果我们有100个任务要执行,但内核只能提供99个信号量怎么办?糟糕的事情发生了.我们可以重建代码只使用一个信号量,虽然等待它会显得有些不稳定.顺便说一下,这样做实际上完全消除了调度组,所以我们基本上用信号量替换了组.让我们来看吧!
NSUInteger numKeys = [keys count];
// set the count of the semaphore to the number of times it must be signalled before
// being exhausted. Up to `numKeys` waits will actually wait for signals this way.
// Additional waits will return immediately.
dispatch_semaphore_t sem = dispatch_semaphore_create(numKeys);
for (int i = 0; i < numKeys; i++) {
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (NSUInteger i = 0; i < numKeys; i++) {
__block NSString *key = [keys objectAtIndex:i];
dispatch_async(queue, ^{
[self postImage:[images objectForKey:key] completionHandler:^(ServerResponse *response){
...;
// This decrements the semaphore's count by one. The calling code will be
// woken up by this, and will then wait again until no blocks remain to wait for.
dispatch_semaphore_signal(sem);
}];
});
}
// At this point, all the work is running (or could have already completed, who knows?).
// We don't want this function to continue running until we know all of the blocks
// have run, so we wait on our semaphore a number of times equalling the number
// of signals we expect to get. If all the blocks have run to completion before we've
// waited for all of them, the additional waits will return immediately.
for (int i = 0; i < numKeys; i++) {
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}
// Now all the tasks should have completed.
dispatch_release(sem);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8469 次 |
| 最近记录: |