正确使用Core Data多线程的3种方式

#Pragma Conference 2015会议上,Marcus Zarra,撰写过关于Core DataCore Animation的书,叙述了三种在多线程环境下使用Core Data的方法并且设法解决在2015年应如何使用Core Data的问题。实际上,Zarras说道,当用一个拥有十一年历史的技术比如Core Data工作时,你所面临的问题之一是有大量的信息是可用的,不过查明哪一份信息依旧精确以及哪一份不精确并不是一件简单的事。

根据Zarras所言,当我们知道我们仍旧有空余的CPU时我们应该使用多线程,那样我们可以预先处理用户接下来要使用的数据。多线程另外一个很重要的用例是通过允许用户不必等待一个冗长的操作来完成,来改进一个app的灵敏程度,比如网络操作。多线程几乎从来不是解决性能问题的办法并且它是一种基础设计决策,而不是一个事后的想法。

最初的方法

最初的方法是在iOS 6推出之前唯一可用的方法。这个方法现在依然可以使用,尽管Zarra建议除了在某些极端情况以外不要使用它。它基于四个主要的原则:

  • 一个NSPersistentStoreCoordinator(PSC)处理所有磁盘之间的相互影响。
  • NSManagedObjectContexts (MOCs)与PSC对话并且不知道对方的任何情况。
  • 其中一个MOCs负责UI的更新并且在单一可信来源上起作用。
  • 一个MOC开始意识到另一个MOC的变化的唯一方法是通过merging 合并处理一个NSNotification。

这个设计有一些不足之处,比如需要写很多公式化的代码,线程规则不明确会导致不定时发生崩溃以及意外线程阻塞。随着推出了iOS 8,这些问题改善了一些。并且多亏了一个debug flag调试标志,Yosemite才能在它违反Core Data并发模型的时候让应用程序崩溃。

艰难的方法

Zarras称之为艰难的方法的是一个依赖于用于多进程访问SQLite的方法。这就意味着我们可以拥有多个PSC,让每个MOC都可以拥有自己的PSC。这会对摆脱任何锁定问题起到很好的作用并且启用几乎所有异步访问——除非你没有写相同的表以及同时把两个PSC排成一行。

即使有了这个设计,只用一个MOC来把数据反馈到UI是可取的。这个方法会让用PSC来同步数据变得艰难,因为它们不知道对方的任何情况。此外,线程和可维护性也会被损害。这个方法有趣的一面在于,这就是iCloud如何运作的真实写照。

最好的方法

根据Zarra所言,最好的办法并不是速度最快的,但它是到目前为止最简单和最可持续的方法。它依靠苹果和iOS 6一起推出的new APIs,new APIs允许定义子MOC并且详细描述一个MOC的并发类型。Zarra呈现的这个设计是基于NSManagedDocument如何运作和使用的:

  • 一个单独的持久性数据协调器。
  • 唯一能实际访问PSC的一个私有的MOC。
  • 一个主要的MOC联合UI,它是私有的MOC的子设备。
  • 多个子MOC具体到辅助线程。

这个设计的好处是子MOC所有的变化会自动传送到其主MOC上,因此消除了合并的需求。

这个设计的主要缺陷是它速度缓慢,尽管只是慢了百分之几,Zarra说道。它有一个很棘手的问题就是如果进行太多的异步操作,有可能会在UI上起连锁反应,因为其相关的MOC会受到序列的多重变化,这可能与另一个并不相干。

这个设计一个很重要的细节就是最好不要重复使用很便宜就能创造的子MOC。另一方面,能用很久的子MOC应该与主MOC手动保持同步,因为变化仅仅是从子MOC到主MOC而反之则不行。

Zarra的最后评论是使用NSManagedDocument会锁定UI,所以你最好做好准备

查看英文原文:Three Ways to Get Core Data Multithreading Right

时间: 2024-10-13 06:48:30

正确使用Core Data多线程的3种方式的相关文章

不再为Core Data多线程编程而头疼

by Saul Mora原文链接:http://www.cimgf.com/2011/05/04/core-data-and-threads-without-the-headache/ 我知道我曾经提到我要写一篇关于定制fetch requests的文章,然而,在我为Active Record Fetching project(现在已经改名为MagicalRecord)编写了一些代码之后,我觉得写一篇关于fetching–threading.的文章更好一些. 当大多数cocoa开发者提到Core

iOS Core data多线程并发访问的问题

大家都知道Core data本身并不是一个并发安全的架构:不过针对多线程访问带来的问题,Apple给出了很多指导:同时很多第三方的开发者也贡献了很多解决方法.不过最近碰到的一个问题很奇怪,觉得有一定的特殊性,与大家分享一下. 这个问题似乎在7.0.1以前的版本上并不存在:不过后来我升级版本到了7.0.4.app的模型很简单,主线程在前台对数据库进行读写,而后台线程不断地做扫描(只读).为此每个线程中各创建了一个NSManagedObjectContext. 这个模型其实有点奇怪,因为普遍的模型是

IOS 创建和使用多线程的6种方式

非原创  文字来自:http://www.cnblogs.com/yuanjianguo2012/p/3725480.html   纯属复制 进程和线程概念: 一个程序包含一个以上的进程,而一个进程又可以包含一个以上的线程,每一个进程都有自己独立的内存空间,相应的一个进程中的所有线程都共享该内存空间. 进程:是一个具有一定独立功能的程序关于某个数据集合的一次运行活动.它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的资 源分配单元,也是基本的执行单元.独立的地址空间使得不同的进程

java实现多线程的三种方式

java中实现多线程的方法有两种:继承Thread类和实现runnable接口 1.继承Thread类,重写父类run()方法   public class thread1 extends Thread {           public void run() {                 for (int i = 0; i < 10000; i++) {                         System.out.println("我是线程"+this.get

Java实现多线程的两种方式

实现多线程的两种方式: 方式1: 继承Thread类 A: 自定义MyThread类继承Thread类 B: 在MyThread类中重写run() C: 创建MyThread类的对象 D: 启动线程对象. 问题: a. 为什么要重写run方法? run()方法里封装的是被线程执行的代码 b. 启动线程对象用的是哪个方法? start()方法 c. run()和start()方法的区别? 直接调用run方法只是普通的方法调用 调用start方法先会启动线程,再由jvm调用run()方法 方式2:

c#使用多线程的几种方式示例详解

本文转载自:http://www.jb51.net/article/46234.htm 本文章主要介绍了c#使用多线程的几种方式,通过示例学习c#的多线程使用方式,大家参考使用吧 (1)不需要传递参数,也不需要返回参数 ThreadStart是一个委托,这个委托的定义为void ThreadStart(),没有参数与返回值. 复制代码 代码如下: class Program { static void Main(string[] args) { for (int i = 0; i < 30; i

java 实现多线程的两种方式

一.问题引入 说到这两个方法就不得不说多线程,说到多线程就不得不提实现多线程的两种方式继承Thread类和实现Runable接口,下面先看这两种方式的区别. 二. Java中实现多线程的两种方式 1.  继承Thread类 /** * 使用Thread类模拟4个售票窗口共同卖100张火车票的程序,实际上是各卖100张 */ public class ThreadTest { public static void main(String[] args){ new MyThread().start(

线程的状态以及创建多线程的三种方式

首先了解一下线程的五种状态: 新建状态: 新建状态是指new之后,即新创建了一个线程的时候,此时并未运行任何线程方法体内的程序代码. 就绪状态: 简单来说就是指程序调用了start()之后,线程就得到了启动,代表线程进入了就绪状态,但是此时并不代表它会立刻去执行run()方法体内的程序代码,而是随时等待cpu的调度. 运行状态: 获得cpu的时间后,调用run()方法,进入运行状态. 阻塞状态: 由于某种原因放弃了cpu的会用权力,暂时停止运行,等待再次被调用. 死亡状态: 线程正常执行完毕,或

.Net Core WebApi上传图片的两种方式

我这边主要是为了上传图片,话不多说,上代码. 方式一:通过Form表单上传 后端: /// <summary> /// 上传图片,通过Form表单提交 /// </summary> /// <returns></returns> [Route("Upload/FormImg")] [HttpPost] public ActionResult UploadImg(List<IFormFile> files) { if (file