【问题标题】:GCD for simple download queue用于简单下载队列的 GCD
【发布时间】:2017-01-30 08:20:46
【问题描述】:

我想创建一个简单的下载队列,我不需要太多功能,只需要一个串行队列,这样当我运行我的下载过程时,它只会等待第一次下载完成,然后再开始第二次下载。我正在使用 parse-server,它无论如何都会在后台运行其查询和获取数据功能,但它似乎同时运行。

我正在考虑只使用 GCD,因为当解析服务器功能正在处理这个问题时,我没有直接看到需要使用创建 NSURL 会话来下载我的文件。

为此我定义了一个队列:

let downloadQueue = DispatchQueue(label: "downloadQueue", qos: .background)

然后认为将我的下载功能包装在这个队列中会将要下载的项目添加到队列的后面。但是,这似乎没有发生,文件一被选中就会开始下载。

func downloadDataToDevice(cell: JourneyCollectionViewCell, selectedIndexPath: IndexPath){

    self.downloadQueue.async {

        // query and progressBlock to track download progress
    }
}

【问题讨论】:

  • 你在cellForRow中打电话给downloadDataToDevice吗?
  • self.downloadQueue.sync 也许?
  • 我也试过了。一样。这可能与 parse 如何运行它的查询有关,但我认为 GCD 不会在 block util 中运行代码,因为其他任务已完成。
  • 问题在于分派的代码本身是异步的。理论上,您可以使用信号量使调度的块等待异步调用(在进程中占用一个线程),或者更好地使用OperationQueue 而不是自定义异步Operation 子类。它还为使用maxConcurrentOperationCount 控制并发程度打开了大门(因为按顺序下载会遭受惊人的性能损失)。
  • 更激进的做法是,如果下载大型资产,请在后台 URLSession 进行下载,这样您就可以完全脱离调度队列或操作队列,URLSession 将管理这些资源你,即使在你的应用程序终止后,这在进行大量下载时非常有用。当用户可以离开并使用他们的设备做更有成效的事情时,为什么还要坐在那里盯着一个正在下载的应用程序。 (如果在 iOS 中这样做,这尤其有用。)

标签: swift asynchronous grand-central-dispatch


【解决方案1】:

创建调度队列

为了让您确定问题的原因,我们必须更详细地介绍。首先,您创建的dispatchQueue 是一个serial 队列。这意味着添加到队列中的任何块都将以串行方式执行。 GCD 不保证这些执行的时间,只保证它们的执行顺序。请记住,GCD 不会指定您的代码将在哪个线程上执行,只会将服务质量视为.background

添加块

现在,在将代码块添加到串行队列时,您可以调用队列中的 .sync.async 方法。这些分类器确实确定您添加到队列中的代码块是否将相对于当前线程同步或异步执行。所以如果你在队列中添加一个代码块.sync,GCD会阻塞当前线程,直到代码执行完毕。如果你在队列中添加了代码块.async,那么当前线程会在GCD的判断下继续执行。 DispatchQueue 本身仍然是一个串行队列,无论您是否向其添加代码块 .sync.async

执行块

现在开始您的 Parse 代码,因为这可能会有些棘手。我们已经确定您的DispatchQueue 是一个serial 队列。但是,假设您将一段代码添加到队列中,该代码块在后台执行某些操作(例如下载文件)并具有一些回调函数。从DispatchQueue和代码块所在的线程来看,只要你启动后台动作,这块代码就已经执行完毕,它会进入下一个代码块。队列。这是一个澄清一点的例子:

downloadQueue.async {
    Parse.doSomethingAsync("something", callback: {(error: Error) in
        // Do something else ...
    }
}

正如您在此处看到的,当 GCD 执行此代码块时,doSomethingAsync 方法将在后台运行,具体取决于 Parse API 如何实现该方法。如果我没记错的话,解析 API 对同步或异步行为有不同的功能。只要doSomethingAsync 被调用并在后台开始执行,这段代码就已经完成了执行,GCD 就可以开始执行下一个代码块了……即使从你的角度来看,代码还没有完成,因为文件没有完成下载。 以下代码不会遇到此问题:

downloadQueue.async {
    Parse.doSomethingSync("something", callback: {(error: Error) in
        // Do something else ...
    }
}

因为doSomethingSync 将在当前线程上执行相对于块的操作,并且块将暂停执行,直到它执行完doSomethingSync 方法。

TLDR 和更多信息

TLDR;您需要确保 GCD 块中的下载操作是串行的,并且会在下载发生时阻止执行。

本教程更详细地介绍了 GCD:https://www.raywenderlich.com/60749/grand-central-dispatch-in-depth-part-1

【讨论】:

  • 感谢您的信息。认为我可能不得不使用 url session 方法,因为它似乎使用没有背景块的解析查询来占用线程。
猜你喜欢
  • 2013-06-29
  • 1970-01-01
  • 2013-01-05
  • 2012-12-17
  • 2013-10-11
  • 1970-01-01
  • 2012-09-26
  • 1970-01-01
  • 2021-09-06
相关资源
最近更新 更多