您的位置:首页 > 移动开发 > IOS开发

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

2015-11-28 22:37 381 查看
什么是线程安全?线程安全是怎么完成的(原理)?

线程安全就是说多线程访问同一代码,不会产生不确定的结果。编写线程安全的代码是低依靠线程同步。

多线程最大的好处是可以将其他任务从main UI中解耦出来,这样UI就不会阻塞或冻结。

利用所有的内核和处理器:

比如说加载图片 SDwebImage 采取的是多线程 不会堵塞 如果不多线程就得加载完图片后才继续

 Grand Central Dispatch(GCD):系统管理线程,你不需要编写线 程代码。只需定义想要执行的任务,然后添加到适当的 dispatch queue。GCD 会负责创建线程和调度你的任务。系统直接提供线 程管理,比应用实现更加高效。

 Operation Queue:Objective-C 对象,类似于 dispatch queue。你 定义想要执行的任务,并添加任务到 operation queue,后者负责 调度和执行这些任务。和 GCD 一样,Operation Queue 也管理了 线程,更加高效。

所有 operation objects 都支持以下关键特性:

 支持建立基于图的operation objects依赖。可以阻止某个operation 运行,直到它依赖的所有 operation 都已经完成。

 支持可选的 completion block,在 operation 的主任务完成后调用。

 支持应用使用 KVO 通知来监控 operation 的执行状态。

 支持 operation 优先级,从而影响相对的执行顺序

 支持取消,允许你中止正在执行的任务

dispatch queue 是类似于对象的结构体,管理你提交给它的任务,而且都是 先进先出的数据结构。因此 queue 中的任务总是以添加的顺序开始执行。GCD 提供了几种 dispatch queues,不过你也自己创建。

CoreData对多线程的支持比较奇怪(按照一般的思路来说),CoreData的NSPersistentStoreCoordinator和 NSManagedObjectContext对象都是不能跨线程使用的,NSManagedObject也不行,有人想加锁不就完了。No,作为一个处 女座是不能忍受这么丑陋的解决方案的。其实NSManagedObjectContext已经对跨线程提供了内置的支持,只不过方式比较特殊,需要脑洞大 开才行。

在创建NSManagedObject的时候有个构造器参数initWithConcurrencyType就是解决的关键所在,这个参数是一个枚举,有三个可选值:

NSConfinementConcurrencyType (或者不加参数,默认就是这个)

NSMainQueueConcurrencyType (表示只会在主线程中执行)

NSPrivateQueueConcurrencyType (表示可以在子线程中执行)

 的iOS 5.0苹果为的coredata的并发处理添加了两个内容。

首先介绍第一个:   (推荐)

 - (ID)initWithConcurrencyType:(NSManagedObjectContextConcurrencyType)CT

NSManagedObjectContextConcurrencyType一共有三种:

NSConfinementConcurrencyType

NSPrivateQueueConcurrencyType

NSMainQueueConcurrencyType

NSConfinementConcurrencyType:每一条线程只能有唯一的一个ManagedObjectContext的模式。与此相对应,苹果的官方文档给出了两种解决并发问题的方案:

为每个线程创建一个单独的管理对象内容和共享一个持久性存储协调员。这是典型的推荐方法。

创建一个单独的管理对象上下文和持久性存储协调员为每个线程。这种方法提供了在更大的复杂性为代价更大的并发性(特别是如果你需要不同的沟通环境之间的更改),并增加了内存的使用。

NSPrivateQueueConcurrencyType  与 NSMainQueueConcurrencyType :分别对应绑定一个后台线程与主线程。可以使用performBlock:开执行原来需要使用dispatch_async封装的代码.

NSConfinementConcurrencyType不能执行performBlock。

第二个内容:嵌套ManagedObjectContext

嵌套的环境让你建立一个托管对象的上下文,以便它访问数据从父上下文,而不是从持久性存储。如果您从具有父上下文管理对象上下文请求的对象,核心数据会先 在父。如果父上下文在内存中的对象时,你会得到一个新的管理对象就是这样的。所以,如果有变化的父,你会得到更改版本的对象。如果该对象没有在这方面存在 的,它会持续上涨,通过父上下文,直到它最后就会从持久性存储的数据。

也就是说,当子上下文中做保存操作时,因为子方面没有persistentStoreCoordinator 来合并异步操作到主线程,这也是这种结构的方便之处。

对于这种结构,我找到了来自弗洛里安·库格勒的几种并发策略:

策略一:

同样使用了嵌套Ma
b2b1
nagedObjectContext,但是使用了PrivateQueue作为主背景下,对于工人语境作操作将会经由 MainQueue语境最终由MasterContext合并,这个方案的好处在于工Context都是临时工,不需要考虑他们的生命周期。另外的一个好 处是,由于他们不能自动获取到来自父亲的更新,所以这个任务可以再未完成之前随时取消。

关于死锁

无论何时只要对PersistentStoreCoordinator做写的操作都会造成死锁,但是这个方案的一个好处在于,如果只是做读的操作,是从内存中的,所以不会造成死锁。但是死锁的问题还是要考虑进去的。

策略一策略一

示例:

 - (NSManagedObjectContext *)mainThreadContext {

    如果(!_mainThreadContext){

        _mainThreadContext = [[NSManagedObjectContext页头] initWithConcurrencyType:NSMainQueueConcurrencyType];

        _mainThreadContext.parentContext = [自我backgroundContext];

    }

    返回_mainThreadContext;

}

- (NSManagedObjectContext *)backgroundContext {

    如果(!_backgroundObjectContext){

        _backgroundObjectContext = [[NSManagedObjectContext页头] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

        [_backgroundObjectContext setPersistentStoreCoordinator:_storeCoordinator];

        

    }

    返回_backgroundObjectContext;

}

- (NSManagedObjectContext *)temporaryContext {

    NSManagedObjectContext * temporaryContext = [[NSManagedObjectContext页头] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

    temporaryContext.parentContext = [自我mainThreadContext];

    返回temporaryContext;

}

策略二:

传统的方式,两个线程都使用同一个持久化存取器,不使用嵌套的结构,而使用NSManagedObjectContextObjectsDidChangeNotification合并来自其他线程的变化。这种方法处理起来要注意几点

每一条线程都应该是一个独立的ManagedObjectContext  监听NSManagedObjectContextObjectsDidChangeNotification  时,应该传递context,因为系统也可能会发送通知。

什么是线程安全?线程安全是怎么完成的(原理)?

线程安全就是说多线程访问同一代码,不会产生不确定的结果。编写线程安全的代码是低依靠线程同步。

多线程最大的好处是可以将其他任务从main UI中解耦出来,这样UI就不会阻塞或冻结。

利用所有的内核和处理器:

比如说加载图片 SDwebImage 采取的是多线程 不会堵塞 如果不多线程就得加载完图片后才继续

 Grand Central Dispatch(GCD):系统管理线程,你不需要编写线 程代码。只需定义想要执行的任务,然后添加到适当的 dispatch queue。GCD 会负责创建线程和调度你的任务。系统直接提供线 程管理,比应用实现更加高效。

 Operation Queue:Objective-C 对象,类似于 dispatch queue。你 定义想要执行的任务,并添加任务到 operation queue,后者负责 调度和执行这些任务。和 GCD 一样,Operation Queue 也管理了 线程,更加高效。

所有 operation objects 都支持以下关键特性:

 支持建立基于图的operation objects依赖。可以阻止某个operation 运行,直到它依赖的所有 operation 都已经完成。

 支持可选的 completion block,在 operation 的主任务完成后调用。

 支持应用使用 KVO 通知来监控 operation 的执行状态。

 支持 operation 优先级,从而影响相对的执行顺序

 支持取消,允许你中止正在执行的任务

dispatch queue 是类似于对象的结构体,管理你提交给它的任务,而且都是 先进先出的数据结构。因此 queue 中的任务总是以添加的顺序开始执行。GCD 提供了几种 dispatch queues,不过你也自己创建。

CoreData对多线程的支持比较奇怪(按照一般的思路来说),CoreData的NSPersistentStoreCoordinator和 NSManagedObjectContext对象都是不能跨线程使用的,NSManagedObject也不行,有人想加锁不就完了。No,作为一个处 女座是不能忍受这么丑陋的解决方案的。其实NSManagedObjectContext已经对跨线程提供了内置的支持,只不过方式比较特殊,需要脑洞大 开才行。

在创建NSManagedObject的时候有个构造器参数initWithConcurrencyType就是解决的关键所在,这个参数是一个枚举,有三个可选值:

NSConfinementConcurrencyType (或者不加参数,默认就是这个)

NSMainQueueConcurrencyType (表示只会在主线程中执行)

NSPrivateQueueConcurrencyType (表示可以在子线程中执行)

 的iOS 5.0苹果为的coredata的并发处理添加了两个内容。

首先介绍第一个:   (推荐)

 - (ID)initWithConcurrencyType:(NSManagedObjectContextConcurrencyType)CT

NSManagedObjectContextConcurrencyType一共有三种:

NSConfinementConcurrencyType

NSPrivateQueueConcurrencyType

NSMainQueueConcurrencyType

NSConfinementConcurrencyType:每一条线程只能有唯一的一个ManagedObjectContext的模式。与此相对应,苹果的官方文档给出了两种解决并发问题的方案:

为每个线程创建一个单独的管理对象内容和共享一个持久性存储协调员。这是典型的推荐方法。

创建一个单独的管理对象上下文和持久性存储协调员为每个线程。这种方法提供了在更大的复杂性为代价更大的并发性(特别是如果你需要不同的沟通环境之间的更改),并增加了内存的使用。

NSPrivateQueueConcurrencyType  与 NSMainQueueConcurrencyType :分别对应绑定一个后台线程与主线程。可以使用performBlock:开执行原来需要使用dispatch_async封装的代码.

NSConfinementConcurrencyType不能执行performBlock。

第二个内容:嵌套ManagedObjectContext

嵌套的环境让你建立一个托管对象的上下文,以便它访问数据从父上下文,而不是从持久性存储。如果您从具有父上下文管理对象上下文请求的对象,核心数据会先 在父。如果父上下文在内存中的对象时,你会得到一个新的管理对象就是这样的。所以,如果有变化的父,你会得到更改版本的对象。如果该对象没有在这方面存在 的,它会持续上涨,通过父上下文,直到它最后就会从持久性存储的数据。

也就是说,当子上下文中做保存操作时,因为子方面没有persistentStoreCoordinator 来合并异步操作到主线程,这也是这种结构的方便之处。

对于这种结构,我找到了来自弗洛里安·库格勒的几种并发策略:

策略一:

同样使用了嵌套ManagedObjectContext,但是使用了PrivateQueue作为主背景下,对于工人语境作操作将会经由 MainQueue语境最终由MasterContext合并,这个方案的好处在于工Context都是临时工,不需要考虑他们的生命周期。另外的一个好 处是,由于他们不能自动获取到来自父亲的更新,所以这个任务可以再未完成之前随时取消。

关于死锁

无论何时只要对PersistentStoreCoordinator做写的操作都会造成死锁,但是这个方案的一个好处在于,如果只是做读的操作,是从内存中的,所以不会造成死锁。但是死锁的问题还是要考虑进去的。

策略一策略一

示例:

 - (NSManagedObjectContext *)mainThreadContext {

    如果(!_mainThreadContext){

        _mainThreadContext = [[NSManagedObjectContext页头] initWithConcurrencyType:NSMainQueueConcurrencyType];

        _mainThreadContext.parentContext = [自我backgroundContext];

    }

    返回_mainThreadContext;

}

- (NSManagedObjectContext *)backgroundContext {

    如果(!_backgroundObjectContext){

        _backgroundObjectContext = [[NSManagedObjectContext页头] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

        [_backgroundObjectContext setPersistentStoreCoordinator:_storeCoordinator];

        

    }

    返回_backgroundObjectContext;

}

- (NSManagedObjectContext *)temporaryContext {

    NSManagedObjectContext * temporaryContext = [[NSManagedObjectContext页头] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

    temporaryContext.parentContext = [自我mainThreadContext];

    返回temporaryContext;

}

策略二:

传统的方式,两个线程都使用同一个持久化存取器,不使用嵌套的结构,而使用NSManagedObjectContextObjectsDidChangeNotification合并来自其他线程的变化。这种方法处理起来要注意几点

每一条线程都应该是一个独立的ManagedObjectContext  监听NSManagedObjectContextObjectsDidChangeNotification  时,应该传递context,因为系统也可能会发送通知。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: