GCD串行队列似乎未按顺序执行 [英] GCD serial queue does not seem to execute serially

查看:144
本文介绍了GCD串行队列似乎未按顺序执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个方法,有时可以在我的整个代码中调用它.下面是一个非常基本的示例,因为该代码处理了iPhone相册中的图像和文件,并标记了使用该方法完成后已处理的图像.

I have a method that at times can be invoked throughout my code. Below is a very basic example, as the code processes images and files off of the iphone photo gallery and marks them already processed when done with the method.

@property (nonatomic, assign) dispatch_queue_t serialQueue;

....

-(void)processImages
{
    dispatch_async(self.serialQueue, ^{
        //block to process images
        NSLog(@"In processImages");

        ....

        NSLog(@"Done with processImages");
    });
}

我认为每次调用此方法时,我都会得到以下输出... 在processImages中" 使用processImages完成" 在processImages中" 使用processImages完成" 等等...

I would think that each time this method is called I would get the below output... "In processImages" "Done with processImages" "In processImages" "Done with processImages" etc...

但我总是得到

在processImages中" 在processImages中" 使用processImages完成" 使用processImages完成" 等等...

"In processImages" "In processImages" "Done with processImages" "Done with processImages" etc...

我认为串行队列会等到第一个块完成后再开始.在我看来,它正在启动该方法,然后再次调用它,并在第一个调用甚至未完成之前就启动,从而创建了通常不会被处理的图像副本,因为如果它确实是串行执行的,则该方法会知道它们的事实.已经被处理.也许我对串行队列的理解不是具体的.有输入吗?谢谢你.

I thought a serial queue would wait till the first block is done, then start. To me it seems it is starting the method, then it gets called again and starts up before the first call even finishes, creating duplicates of images that normally would not be processed due to the fact that if it really executed serially the method would know they were already processed. Maybe my understanding of serial queues is not concrete. Any input? Thank you.

MORE在下面的上下文中,这是块中正在发生的事情……这可能会导致问题吗?

MORE Context below, this is what is going on in the block...Could this cause the issue???

@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;
}

此对象仅创建一次,据我所知,永远不会根据我的代码再次创建...我将运行测试以确保成功.

this object is only created once, and as far as I can tell can never be created again based off my code...I will run tests to make sure though.

更新2:我认为发生了什么,如果您同意/不同意,请对此发表评论.

UPDATE 2: WHAT I THINK IS HAPPENING, please comment on this if you agree/disagree....

很明显,我的主要问题是,似乎该代码块是同时执行的,如果重复运行通常不会执行此操作,则创建重复的条目(两次导入同一张照片).在处理照片时,会对其应用脏"位,以确保下次调用该方法时,它会跳过该图像,但这不会发生,并且某些图像会被处理两次.可能是由于我在该serialQueue中使用enumerategroupswithtypes:在第二个队列中枚举了对象吗?

Obviously my main issue is that it seems this block of code is being executed concurrently, creating duplicate entries (importing the same photo twice) when it wouldn't normally do this if it was run serially. When a photo is processed a "dirty" bit is applied to it ensuring the next time the method is invoked it skips this image, but this is not happening and some images are processed twice. Could this be due to the fact I am enumerating the objects in a second queue using enumerategroupswithtypes: within that serialQueue?

  1. 调用processImages
  2. enumerateObjects
  3. 因为它本身是异步的,所以立即从enumerateObjects返回
  4. 结束对processImages的调用

processImages并未真正完成,尽管由于enumerategroups可能仍在运行,但队列可能已完成,因为它在enumerategroups完成工作之前到达了块的末尾.对我来说这似乎是一种可能性?

processImages is not really done though due to the fact that enumerategroups is probably still running but the queue might thing it is done since it reaches the end of the block before enumerategroups is finished working. This seems like a possibility to me?

推荐答案

串行队列绝对会串行执行.但是,不能保证它们在同一线程上执行.

Serial Queues ABSOLUTELY will perform serially. They are not guaranteed to perform on the same thread however.

假设您使用的是相同的串行队列,问题在于,当从不同线程中同时调用NSLog时,不能保证以正确的顺序输出结果.

Assuming you are using the same serial queue, the problems is that NSLog is NOT guaranteed to output results in the proper order when called near simultaneously from different threads.

这是一个示例:

  1. SQ在线程X上运行,发送"In processImages"
  2. 日志显示正在处理"
  3. 线程X上的SQ,发送使用processImages完成"
  4. SQ在线程Y上运行,发送"In processImages"
  5. 日志显示"essImages \ n"

5.之后,NSLog不一定知道要打印的是3还是4.

After 5., NSLog doesn't necessarily know which to print, 3. or 4.

如果您绝对需要按时间排序的日志记录,则需要专用的队列进行记录.实际上,我只使用主队列就没有问题:

If you absolutely need time ordered logging, You need a dedicated queue for logging. In practice, I've had no problems with just using the main queue:

dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"whatever");
});

如果所有NSlog调用都在同一队列中,那么您应该不会遇到此问题.

If all NSlog calls are the on the same queue, you shouldn't have this problem.

这篇关于GCD串行队列似乎未按顺序执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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