7

我正面临我的应用程序的设计问题。


基本上,以下是我将在我的应用程序中执行的操作。

单个任务是这样的:

  1. 从底层 CoreData 数据库中读取自定义对象
  2. 从 url 下载 json
  3. 解析 json 以更新自定义对象或创建一个新对象(解析可能需要 1 - 3 秒,大数据)
  4. 分析自定义对象(会涉及一些计算,可能需要 1 - 5 秒)
  5. 将自定义对象保存到 CoreData 数据库中。

可能有许多任务同时执行。

一项任务中的步骤显然是ordered(即,没有第 2 步下载 json,第 3 步无法继续),但它们也可以是discrete. 我的意思是,例如,task2 的第 4 步可以在 task1 的第 3 步之前执行(如果 task2 的下载速度可能比 task1 的快)

任务有优先级。用户可以启动具有更高优先级的任务,因此将尝试在所有其他步骤之前执行该任务的所有步骤。


我希望 UI 可以尽可能地响应。

所以我打算创建一个优先级最低的 NSThread。

我在该线程中放置了一个自定义优先级事件队列。任务的每一步都成为一个事件(工作单元)。因此,例如,第 1 步下载 json 成为一个事件。下载后,该事件为第 3 步生成另一个事件并放入队列中。每个事件都有自己的优先级设置。


现在我看到这篇文章:并发和应用程序设计。苹果建议我们Move Away from Threads使用GCDor NSOperation

我发现这NSOperation非常符合我的草稿设计。但我有以下问题:

  • 考虑到 iPhone/iPad cpu 核心,我应该只使用一个 NSOperationQueue 还是创建多个?
  • NSOperationQueue 或 NSOperation 会以最低的线程优先级执行吗?执行是否会影响 UI 响应(我关心,因为这些步骤涉及计算)?
  • 我可以从另一个生成一个 NSOperation 并将其放入队列吗?我在 NSOperation 中没有看到队列属性,我怎么知道队列?
  • 如何将 NSOperationQueue 与 CoreData 合作?每次访问 CoreData 时,我应该创建一个新的上下文吗?那会贵吗?
  • 一个任务的每一步都变成了一个NSOperation,这样的设计对吗?

谢谢

4

5 回答 5

4

考虑到 iPhone/iPad cpu 核心,我应该只使用一个 NSOperationQueue 还是创建多个?

在大多数情况下,两个(CPU、网络+I/O)或三个(CPU、网络、I/O)串行队列应该可以很好地工作,以保持应用程序响应并且您的程序流式处理按照它们绑定的内容工作。当然,您可能会发现另一种组合/公式适用于您的特定工作分配。

NSOperationQueue 或 NSOperation 会以最低的线程优先级执行吗?执行是否会影响 UI 响应(我关心,因为这些步骤涉及计算)?

默认情况下不是。看看-[NSOperation setThreadPriority:]是否要降低优先级。

我可以从另一个生成一个 NSOperation 并将其放入队列吗?我在 NSOperation 中没有看到队列属性,我怎么知道队列?

当然。如果您使用我概述的串行方法,则很容易找到正确的队列——或者您可以使用 ivar。

如何将 NSOperationQueue 与 CoreData 合作?每次访问 CoreData 时,我应该创建一个新的上下文吗?那会贵吗?

(没有意见)

一个任务的每一步都变成了一个NSOperation,这样的设计对吗?

是的 - 将您的队列划分为它所绑定的资源是一个好主意。

于 2012-09-05T14:51:14.393 回答
0
  • 从外观上看,NSOperationQueue 就是您所追求的。您可以设置同时运行的并发操作数。如果使用多个 NSOperation,它们将同时运行……除非您自己处理队列,这与使用 NSOperationQueue 相同

  • 线程优先级……我不太清楚你的意思,但是在iOS中,UI绘制、事件和用户交互都是在主线程上运行的。如果您在后台线程上运行,无论您运行的操作多么复杂或占用大量 CPU 资源,界面仍然会响应

  • 您应该在主线程上生成和处理操作,因为它不会花费任何时间,您只需在后台线程中运行它们,这样您的主线程就不会被锁定

  • CoreData,我并没有专门使用它,但是到目前为止,每个Core~我都使用它在后台线程上完美运行,所以它应该不是问题

  • 就设计而言,这只是一个观点......至于我,我会为每个任务设置一个 NSOperation,并让它处理所有步骤。如果您想提供一些反馈或继续其他下载或其他内容,可能会在步骤完成时编写回调

于 2012-09-05T14:48:19.820 回答
0

多线程时计算的影响不会因为您使用 NSThread 而不是 NSOperation 而有所不同。但是请记住,当前的 iOS 设备必须使用双核处理器。

你的一些问题不是很具体。你可能想也可能不想使用多个 NSOperationQueue。这完全取决于你想如何处理它。如果你有不同的 NSOperation 子类或不同的 NSBlockOperations,你可以通过使用优先级来管理执行顺序,或者你可能希望为不同类型的操作使用不同的队列(尤其是在使用串行队列时)。我个人更喜欢在处理相同类型的操作时使用 1 个操作队列,当操作不相关/不可靠时使用不同的操作队列。这使我可以灵活地根据发生的事情(网络中断、应用程序进入后台)取消和停止队列中的操作。

我从来没有找到一个很好的理由来根据当前操作执行期间发生的事情添加操作。如果你需要这样做,你可以使用 NSOperationQueue 的类方法 currentQueue,它会给你当前操作正在运行的操作队列。

如果您正在使用 NSOperation 进行核心数据工作,我建议为每个特定操作创建一个上下文。确保在 main 方法中初始化上下文,因为这是您在 NSOperation 后台执行的正确线程上的位置。

您不一定需要为每个任务拥有一个 NSOperation 对象。您可以下载数据并在 NSOperation 中对其进行解析。您还可以抽象地进行数据下载,并使用 NSOperation 的完成块属性对下载的内容进行数据操作。这将允许您使用相同的对象来获取数据,但有不同的数据操作。

我的建议是阅读 NSOperation、NSBlockOperation 和 NSOperationQueue 的文档。检查您当前的设计,了解如何使这些类适应您当前的项目。我强烈建议你走 NSOperation 家族而不是 NSThread 家族的路线。

祝你好运。

于 2012-09-05T14:53:55.370 回答
0

只是添加到@justin的答案

如何将 NSOperationQueue 与 CoreData 合作?每次访问 CoreData 时,我应该创建一个新的上下文吗?那会贵吗?

NSOperation与 Core Data 一起使用时应该非常小心。
必须始终记住的是,如果您想在单独的线程上运行 CoreData 操作,您必须NSManagedObjectContext为该线程创建一个新线程,并共享主线程的托管对象上下文持久存储协调器(“主”MOC 是应用程序委托)。

此外,该线程的新托管对象上下文是从该线程创建的,这一点非常重要。因此,如果您打算使用 Core Data,请确保在 NSOperation 的方法中初始化新的 MOC,而不是.NSOperationmaininit

是一篇关于核心数据和线程的非常好的文章

于 2012-09-05T15:51:05.730 回答
-1

使用 GCD - 它是一个比 NS* 更好的框架

将所有 CoreData 访问权保留在一个队列上,并在例程结束时使用 dispatch_async 以保存回 CoreData 数据库。

如果您有开发者帐户,请查看此 WWDC 视频:https ://developer.apple.com/videos/wwdc/2012/?id=712

于 2012-09-05T15:34:48.163 回答