当前位置:网站首页>(转载)Multi-Context CoreData 之多线程环境中使用CoreData
(转载)Multi-Context CoreData 之多线程环境中使用CoreData
2022-06-13 12:22:00 【Victor张】
转载以记录,原文看这里:https://www.jianshu.com/p/a4525d4f96bf
CoreData学起来也没有很复杂,我们其实增删改查都和别的ORM大同小异,默认情况下我们的代码都在Main Thread中执行,数据库操作一旦量大了,频繁了,势必会阻塞卡住主线程。
这个世界天然是多线程的,所以我们操作数据也必须多线程。CoreData对多线程的支持比较奇怪(按照一般的思路来说),CoreData的NSPersistentStoreCoordinator(PSC)和NSManagedObjectContext(MOC)对象都是不能跨线程使用的,
NSManagedObject(MO)也不行,有人想加锁不就完了。其实NSManagedObjectContext(MOC)已经对跨线程提供了内置的支持,只不过方式比较特殊,需要脑洞大开才行。
在创建NSManagedObject的时候有个构造器参数initWithConcurrencyType就是解决的关键所在,这个参数是一个枚举,有三个可选值:
- NSConfinementConcurrencyType (或者不加参数,默认就是这个)
- NSMainQueueConcurrencyType (表示只会在主线程中执行)
- NSPrivateQueueConcurrencyType (表示可以在子线程中执行)
那么究竟应该怎么使用才能无阻塞无痛呢?
首先,让我们看一下single-context的架构,如下图,我们需要一个PSC管理磁盘存储,并且我们需要一个MOC来处理增删改查这些操作,
看到上面的架构设计,最大的问题一眼就可以看出来,MOC每次操作PSC都会带来文件IO,性能消耗及线程阻塞,如何解决这个问题呢?这个也很容易想到,在这个多线程的世界里,我们可以用多个MOC就可以了,
在这个多线程的世界里,Core Data也给我们提供了条件。
多重MOC。
先介绍第一种,传统的多重MOC方案,
把每一个MOC想象成做出改动的草稿,在iOS5之前,使用CoreData需要监听其他MOC做出的改变,并且与之融合进主MOC当中(merge到Main MOC中),我们只需要将大多数PSC操作放到子线线程中,并在有数据变化的时候merge到Main Context中,这样就会大大减少Main Context的PSC操作。如下图:
我们需要注册NSManagedObjectContextDidSaveNotification的回调方法,
在该方法中调用mainContext的mergeChangesFromContextDidSaveNotification:notification方法,
将所有的数据变动merge到mainContext中,这样就保持了两个Context中的数据同步。
由于大部分的操作都是privateContext在子线程中操作的,所以这种设计是UI线程耗时最少的一种设计,但是它的代价是需要多写mergeChanges的方法。
下面再介绍一种Mutil-Context 方案, Parent/Child Context(父子Context).
如下图:
这个在iOS5 后,才出现的新特性,
一个父MOC在主线程,多个Child MOC跑在子线程中,并且把他们的Parent Context都设置为同一个Main Context,
这样所有Child Context的Save操作都会被Push up 到Main Context 中, 这样就相当于上面介绍的传统多重Context的
NSManagedObjectContextDidSaveNotification机制,只不过childContext调用save方法,其parentContext不用任何merge操作,CoreData自动将数据merge到parentContext当中,这就省下了写很多mergeChanges的代价和风险。
我们再看一下上面图,有没有发现一个严重的问题–UI线程阻塞严重, PSC是在主线程操作,这样其实也是UI线程阻塞的设计,我们很容易相到一个方案,把PSC放到非主线程的异步线程去跑不就行了,对,那怎么维护各个Child Context线程和数据同步呢,看下图:
这里总共有三种Context,一是连接persistentStoreCoordinator也是最底层的backgroundContext,
二是UI线程的mainContext,三是子线程的privateContext,
后两个Context在上面中已经介绍过了,这里就不再具体介绍,他们的关系是privateContext.parentContext = mainContext,mainContext.parentContext = backgroundContext。
下面说说它的具体工作流程。
在应用中,如果我们有API操作,首先我们会起一个子线程进行API请求,在得到Response后要进行数据库操作,
这是我们要创建一个privateContext进行数据的增删改查,然后call privateContext的save方法进行存储,
这里的save操作只是将所有数据变动Push up到它的父Context中也就是mainContext中,
然后mainContext继续call save方法,将数据变动Push up到它的父Context中也就是backgroundContext,
最后调用backgroundContext的save方法真正将数据变动存储到Disk数据库中,
在这个过程中,前两个save操作相对耗时较少,真正耗时的操作是最后backgroundContext的save操作,因为只有它有Disk IO的操作。
By the way,需要注意一下的是,直接传递在两个不同的MOC当中得到的MO是绝对禁止的。但是有个简单的方法“映射”一个MO:通过它的ObjectID。这个ID是线程安全的,所以总是可以用它来获得MO,方法是objectWithID:, 会返回一个复制了的MO。
边栏推荐
猜你喜欢
That is to say, it launched the industry's first data stream recording PAAS scheme, which can reproduce the recording capacity of large manufacturers at low cost
想发自己的NFT,你要先搞清楚这6个问题
Lucene from introduction to practice
Web development project, web single page development
Lucene从入门到实战
Chenhongzhi: bytegraph, a trillions level graph database developed by byte beating and its application and challenges
Machine learning service helps in application text language online and offline detection
Pulsar 消费者
[tcapulusdb knowledge base] Introduction to tcapulusdb tcapsvrmgr tool (II)
10、DCN 介绍
随机推荐
options请求(跨域预检)
即构推出行业首个数据流录制PaaS方案,低成本复刻头部大厂录制能力
Selenium3 automatic test practice (5)
【管理知多少】“风险登记册”本身的风险
Lucene从入门到实战
Cube 技术解读 | Cube 渲染设计的前世今生
Interpretation of cube technology | past and present life of cube Rendering Design
[management knowledge] risk of "risk register"
A practice of sharing applet configuration
基于STM32F103——DS1302日期时间+串口打印
Methodology of cloud service
003. Torchserve calls LSTM model prediction
Machine learning service helps in application text language online and offline detection
Machine learning (III) - LDA (linear discriminant analysis) theory and code explanation
Wallys/Network_ Card/DR-NAS26/AR9223/2x2 MIMO
5 LockSupport与线程中断
小程序配置分享的一种实践
M1 experience win11
Pointnet: deep learning on point sets for 3D classification and segmentation
我们的B端SaaS为什么生存得如此艰难