串行队列/专用调度队列如何知道任务何时完成? [英] How does a serial queue/private dispatch queue know when a task is complete?

查看:95
本文介绍了串行队列/专用调度队列如何知道任务何时完成?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(或许可以通过串行调度队列如何保证资源保护?但我不明白如何)

(Perhaps answered by How does a serial dispatch queue guarantee resource protection? but I don't understand how)

问题

gcd如何知道异步任务(例如网络任务)完了吗?为此,我应该使用 dispatch_retain dispatch_release 吗? 更新:我无法使用ARC调用这些方法中的任何一种...有什么用?

How does gcd know when an asynchronous task (e.g. network task) is finished? Should I be using dispatch_retain and dispatch_release for this purpose? Update: I cannot call either of these methods with ARC... What do?

详细信息

我正在与进行大量网络访问的第三方库进行交互。我通过一个小类创建了一个包装器,它基本上提供了我需要的第三方类的所有方法,但是在 dispatch_async(serialQueue){() - >中包含调用。在中无效(其中 serialQueue 是我的包装类的成员)。

I am interacting with a 3rd party library that does a lot of network access. I have created a wrapper via a small class that basically offers all the methods i need from the 3rd party class, but wraps the calls in dispatch_async(serialQueue) { () -> Void in (where serialQueue is a member of my wrapper class).

I我试图确保每次对底层库的调用在下一次开始之前完成(某种程度上它还没有在库中实现)。

I am trying to ensure that each call to the underlying library finishes before the next begins (somehow that's not already implemented in the library).

推荐答案

串行调度队列的工作序列化是在直接提交给队列的工作单元上。一旦执行到达提交的闭包的末尾(或它返回),则可以执行队列上的下一个工作单元。

The serialisation of work on a serial dispatch queue is at the unit of work that is directly submitted to the queue. Once execution reaches the end of the submitted closure (or it returns) then the next unit of work on the queue can be executed.

重要的是,关闭可能已经启动的任何其他异步任务可能仍在运行(或者甚至可能尚未开始运行),但不考虑它们。

Importantly, any other asynchronous tasks that may have been started by the closure may still be running (or may not have even started running yet), but they are not considered.

例如,对于以下代码:

dispatch_async(serialQueue) {
    print("Start")
    dispatch_async(backgroundQueue) {
       functionThatTakes10Seconds()
       print("10 seconds later")
    }
    print("Done 1st")
}

dispatch_async(serialQueue) {
    print("Start")
    dispatch_async(backgroundQueue) {
       functionThatTakes10Seconds()
       print("10 seconds later")
    }
    print("Done 2nd")
}

输出类似于:


开始

Start

完成第一次

开始

完成第二次

10秒后

10秒后

请注意,在调度第二个串行任务之前,前10秒任务尚未完成。现在,比较:

Note that the first 10 second task hasn't completed before the second serial task is dispatched. Now, compare:

dispatch_async(serialQueue) {
    print("Start")
    dispatch_sync(backgroundQueue) {
       functionThatTakes10Seconds()
       print("10 seconds later")
    }
    print("Done 1st")
}

dispatch_async(serialQueue) {
    print("Start")
    dispatch_sync(backgroundQueue) {
       functionThatTakes10Seconds()
       print("10 seconds later")
    }
    print("Done 2nd")
}

输出如下:


开始

Start

10秒后

完成第一次

开始

10秒后

完成第二次

注意这次是因为10秒任务是同步调度序列队列被阻止,第二个任务在第一个任务完成之前没有开始。

Note that this time because the 10 second task was dispatched synchronously the serial queue was blocked and the second task didn't start until the first had completed.

在您的情况下,您正在包装的操作很可能会自己调度异步任务(因为这是网络操作的本质),因此串行调度队列本身就是还不够。

In your case, there is a very good chance that the operations you are wrapping are going to dispatch asynchronous tasks themselves (since that is the nature of network operations), so a serial dispatch queue on its own is not enough.

您可以使用 DispatchGroup 来阻止您的串行调度队列。

You can use a DispatchGroup to block your serial dispatch queue.

dispatch_async(serialQueue) {
    let dg = dispatch_group_create()
    dispatch_group_enter(dg)
    print("Start")
    dispatch_async(backgroundQueue) {
       functionThatTakes10Seconds()
       print("10 seconds later")
       dispatch_group_leave(dg)
    }
    dispatch_group_wait(dg)
    print("Done")
}

这将输出


开始

Start

10秒后

完成

dg.wait()阻止串行队列直到的数量 dg.leave 调用与 dg.enter 调用的次数匹配。如果您使用此技术,那么您需要小心确保包装操作的所有可能的完成路径调用 dg.leave 。在 dg.wait()上还有一些带有超时参数的变体。

The dg.wait() blocks the serial queue until the number of dg.leave calls matches the number of dg.enter calls. If you use this technique then you need to be careful to ensure that all possible completion paths for your wrapped operation call dg.leave. There are also variations on dg.wait() that take a timeout parameter.

这篇关于串行队列/专用调度队列如何知道任务何时完成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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