需要澄清从不同队列中调用dispatch_group_create()和dispatch_group_enter()时的dispatch_group_wait()行为 [英] Need clarification on dispatch_group_wait() behavior when dispatch_group_create() and dispatch_group_enter() are called from different queues

查看:110
本文介绍了需要澄清从不同队列中调用dispatch_group_create()和dispatch_group_enter()时的dispatch_group_wait()行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在查看有关使用调度队列在一组任务完成时获得通知的Ray Wenderlich教程. http://www.raywenderlich.com/63338/grand -central-dispatch-in-depth-part-2

I am looking at the Ray Wenderlich tutorial on using dispatch queues to get notified when a group of tasks complete. http://www.raywenderlich.com/63338/grand-central-dispatch-in-depth-part-2

有效的代码"下显示的第一个代码直接来自于本教程.在全部3次下载完成后,将执行Alert视图(最终完成块).

The first code shown under "Code that works" is straight from the tutorial. The Alert view(final completion block) get executed after all 3 downloads complete.

我尝试使用它,并在无效代码"中下移了调度异步,以查看如果dispatch_group_create()和dispatch_group_enter()发生在不同的队列上会发生什么.在这种情况下,dispatch_group_enter()似乎没有注册,因为即使在所有下载完成之前,dispatch_group_wait()也会立即完成并执行警报视图(最终完成块).

I tried to play around with it and moved the dispatch async down in the "Code that does not work" to see what will happen if dispatch_group_create() and dispatch_group_enter() happen on different queues. In this case, the dispatch_group_enter() does not seem to register because the dispatch_group_wait() immediately completes and alert view(final completion block) is executed even before all the downloads have completed.

有人可以解释第二种情况吗? (这只是出于我对调度组如何工作的理解,我意识到最好将整个函数放在全局并发队列中以避免阻塞主线程.)

Can someone explain whats happening in the second case? (This is just for my understanding of how dispatch group works and I realize thats its better to put the entire function in the global concurrent queue to avoid blocking the main thread).

有效的代码

Code that works

 - (void)downloadPhotosWithCompletionBlock:(BatchPhotoDownloadingCompletionBlock)completionBlock
{

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^{

    __block NSError *error;
    dispatch_group_t downloadGroup = dispatch_group_create();

    for (NSInteger i = 0; i < 3; i++)
    {
        NSURL *url;
        switch (i) {
            case 0:
                url = [NSURL URLWithString:kOverlyAttachedGirlfriendURLString];
                break;
            case 1:
                url = [NSURL URLWithString:kSuccessKidURLString];
                break;
            case 2:
                url = [NSURL URLWithString:kLotsOfFacesURLString];
                break;
            default:
                break;
        }


            dispatch_group_enter(downloadGroup);
            __block Photo *photo = [[Photo alloc] initwithURL:url
                                  withCompletionBlock:^(UIImage *image, NSError *_error) {
                                      if (_error) {
                                          error = _error;
                                      }
                                      NSLog(@"Finished completion block for photo alloc for URL %@ and photo is %@",url,photo) ;
                                      dispatch_group_leave(downloadGroup);
                                  }];

            [[PhotoManager sharedManager] addPhoto:photo];
            NSLog(@"Finished adding photo to shared manager for URL %@ and photo is %@",url,photo) ;
    }

    dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER); // 5
    dispatch_async(dispatch_get_main_queue(), ^{
        if (completionBlock) {
            NSLog(@"Executing completion block after download group complete") ;
            completionBlock(error);
        }
    }) ;
  }) ;
}

已编辑的代码不适用于额外的NSLog语句

EDITED Code that does not work with extra NSLog statements

无效的代码

Code that does not work

 - (void)downloadPhotosWithCompletionBlock:(BatchPhotoDownloadingCompletionBlock)completionBlock
 {

__block NSError *error;
dispatch_group_t downloadGroup = dispatch_group_create();

for (NSInteger i = 0; i < 3; i++)
{
    NSURL *url;
    switch (i) {
        case 0:
            url = [NSURL URLWithString:kOverlyAttachedGirlfriendURLString];
            break;
        case 1:
            url = [NSURL URLWithString:kSuccessKidURLString];
            break;
        case 2:
            url = [NSURL URLWithString:kLotsOfFacesURLString];
            break;
        default:
            break;
    }

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^{
        dispatch_group_enter(downloadGroup);
        NSLog(@"Enetered group for URL %@",url) ;
        __block Photo *photo = [[Photo alloc] initwithURL:url
                                      withCompletionBlock:^(UIImage *image, NSError *_error) {
                                          if (_error) {
                                              error = _error;
                                          }
                                          NSLog(@"Finished completion block for photo alloc for URL %@ and photo is %@",url,photo) ;
                                          dispatch_group_leave(downloadGroup);
                                      }];

        [[PhotoManager sharedManager] addPhoto:photo];
        NSLog(@"Finished adding photo to shared manager for URL %@ and photo is %@",url,photo) ;
    }) ;
}

NSLog(@"Executing wait statement") ;
dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER); // 5
dispatch_async(dispatch_get_main_queue(), ^{
    if (completionBlock) {
        NSLog(@"Executing completion block after download group complete") ;
        completionBlock(error);
    }
}) ;
}

推荐答案

"dispatch_group_enter()似乎没有注册",因为在调用dispatch_group_wait()时尚未真正调用它.或更确切地说,不能保证已被调用.有比赛条件.

The "dispatch_group_enter() does not seem to register" because it hasn't actually been called yet by the time that dispatch_group_wait() is called. Or, rather, it's not guaranteed to have been called. There's a race condition.

这不是专门针对不同的队列.这是关于并发性和异步性的.

This isn't specifically about different queues. It's about concurrency and asynchronicity.

dispatch_async()只是意味着将任务添加到列表中",并隐含地理解某处某处何时将某项任务从该列表中删除并执行它们.在将任务放入列表后,它将立即返回到其调用方.它不等待任务开始运行,更不用说完成运行了.

dispatch_async() just means "add a task to a list" with an implicit understanding that something, somewhere, somewhen will take tasks off of that list and execute them. It returns to its caller immediately after the task has been put on the list. It does not wait for the task to start running, let alone complete running.

因此,您的for循环运行非常快,并且在退出时,它可能已经没有开始了排队的任务.或者,如果有任何开始,则可能是他们尚未完成进入群组的操作.

So, your for loop runs very quickly and by the time it exits, it may be that none of the tasks that it has queued have started. Or, if any have started, it may be that they haven't finished entering the group.

您的代码可能会在任何内容进入组之前完成对dispatch_group_wait()的调用.

Your code may complete its call to dispatch_group_wait() before anything has entered the group.

通常,您要确保对dispatch_group_enter()的所有相关调用都已完成,然后才能对dispatch_group_wait()进行调用.最简单的方法是让它们全部在一个执行上下文中同步发生.也就是说,不要在异步分配的块中放置对dispatch_group_enter()的调用.

Usually, you want to be sure that all relevant calls to dispatch_group_enter() have completed before the call to dispatch_group_wait() is made. The easiest way to do that is to have them all happen synchronously in one execution context. That is, don't put calls to dispatch_group_enter() inside blocks that are dispatched asynchronously.

这篇关于需要澄清从不同队列中调用dispatch_group_create()和dispatch_group_enter()时的dispatch_group_wait()行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆