GCD串行队列似乎没有串行执行 [英] GCD serial queue does not seem to execute serially

查看:35
本文介绍了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");
    });
}

我认为每次调用此方法时,我都会得到以下输出...正在处理图像"完成处理图像"正在处理图像"完成处理图像"等等……

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...

但我总是得到

处理中的图像"正在处理图像"完成处理图像"完成处理图像"等等……

"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 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....

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

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. 枚举对象
  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. 日志打印In proc"
  3. 线程 X 上的 SQ,发送Done with processImages"
  4. SQ 在线程 Y 上运行,发送In processImages"
  5. 日志打印essImages "
  1. SQ runs on thread X, sends "In processImages"
  2. log prints "In proc"
  3. SQ on thread X, sends "Done with processImages"
  4. SQ runs on thread Y, sends "In processImages"
  5. log prints "essImages "

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天全站免登陆