草庐IT

iphone - 主线程在执行后台线程时正在等待[NSManagedObjectContext(_NSInternalAdditions)lockObjectStore]

coder 2024-01-21 原文

我正在通过后台线程拥有的新创建的NSManagedObjectContext在后台线程(使用GCD)上执行昂贵的读取操作(约5秒,约30,000个对象)。

但是,我没有在后台执行此操作,因为主线程正在等待持久性存储上的锁定,因此UI被冻结。这是堆栈跟踪:

* thread #1: tid = 0x1c03, 0x3641be78 CoreData`-[NSManagedObjectContext(_NSInternalAdditions) lockObjectStore], stop reason = breakpoint 1.1
    frame #0: 0x3641be78 CoreData`-[NSManagedObjectContext(_NSInternalAdditions) lockObjectStore]
    frame #1: 0x36432f06 CoreData`-[_PFManagedObjectReferenceQueue _processReferenceQueue:] + 1754
    frame #2: 0x36435fd6 CoreData`_performRunLoopAction + 202
    frame #3: 0x35ab9b1a CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 18
    frame #4: 0x35ab7d56 CoreFoundation`__CFRunLoopDoObservers + 258
    frame #5: 0x35ab80b0 CoreFoundation`__CFRunLoopRun + 760
    frame #6: 0x35a3b4a4 CoreFoundation`CFRunLoopRunSpecific + 300
    frame #7: 0x35a3b36c CoreFoundation`CFRunLoopRunInMode + 104
    frame #8: 0x376d7438 GraphicsServices`GSEventRunModal + 136
    frame #9: 0x33547cd4 UIKit`UIApplicationMain + 1080
    frame #10: 0x000f337a MyApp`main + 90 at main.m:16

我(相信)我已经确认在此后台线程正在执行其工作时,我没有访问主线程的NSManagedObjectContext。从堆栈跟踪中可以明显看出,我没有直接对Core Data做任何事情。但是某事触发了对_processReferenceQueue:的调用,这导致尝试锁定存储。有人碰巧知道此方法的作用以及在后台线程执行其工作时如何/是否可以防止它被调用?

编辑

在启动此后台获取之后,我不会在主线程上进行任何Core Data读取或写入操作。这就是为什么如此令人困惑。如果主线程也试图做更多的工作,我希望会引起争执,但这不是-至少,我没有要求这样做。没有读取,没有写入,没有FRC。这就是为什么我想知道是否有人熟悉此_processReferenceQueue方法。为什么叫它?我该怎么办才能导致它运行?

编辑

作为测试,我尝试将MT的MOC设置为没有待定更改的状态,然后再关闭BT进行提取,希望它不需要在_processReferenceQueue中进行任何需要锁定商店。

在启动BT之前,我注意到[MOC updatedObjects]集中只有一个对象。插入或删除的集中没有对象。

调用[MOC save]之后,[MOC updatedObjects]集为空,如预期的那样。
但是,一旦我启动了BT,即使MOC中没有脏东西,MT仍会尝试将商店锁定在_processReferenceQueue中。

我尝试做的下一件事(严格地作为测试)是在启动BT之前调用[MOC reset]。同样,重置后的[MOC updatedObjects]集为空,这与预期的一样。此时,在代码中,直到BT完成工作,我才接触MT上的任何托管对象(因此,由于重置使我已经引用的托管对象无效,因此我没有遇到任何问题)。但是,这次MT做了而不是尝试将持久性存储锁定在_processReferenceQueue中。

这种行为向我表明,在启动BT之后,我没有对MT上的MOC进行任何明确的操作。否则,MT会在_processReferenceQueue内或外的某个位置请求锁定(用于读取或写入)。但事实并非如此。

我不确定为什么最近保存的MOC要求随后锁定_processReferenceQueue,而最近重置的MOC不需要。

我会继续挖掘。

谢谢!
布赖恩

最佳答案

没有更多信息,我所能做的只是猜测。

不幸的是,Core Data没有使用相同的持久性存储协调器为MOC实现读取器/写入器锁定。这意味着对一个线程的读取将阻止其他使用同一持久性存储协调器的线程。

因此,您在后台长时间运行的访存将阻止主线程访存。

您有几种选择。

分解长时间运行的获取,以便按顺序获取小片段。您想进行多次小量获取,而不要在完成当前任务之前再发行下一部分。

这将允许在主线程上进行访存,从而有机会在后台线程上的多个小访存之间进行处理。

另一种选择是创建一个单独的持久性存储协调器,将您的后台MOC连接到该持久性存储协调器,然后运行获取。如果您使用多个持久性存储协调器,那么您可以同时拥有多个阅读器,并且它们不会永久性地相互阻塞。

编辑

I've definitely thought about breaking it up. But this isn't a case where I'm trying to make two simultaneous fetches play nicely together. The MT shouldn't be touching Core Data at this point. – BrianJStafford



您是在使用UIManagedDocument还是在主线程上创建了MOC,还是使用NSMainQueueConcurrencyType

我问,因为Core Data确保每次通过运行循环都处理所有“用户事件”。我从没想过要确切地确定该如何完成,但是我想他们会在主线程上的MOC的运行循环中添加一个处理程序。

核心数据非常易于使用,除非您有多个MOC。然后,交互是如此复杂,以至于没有实际代码就很难确定正在发生的事情。

如果可以,请发布创建任何/所有MOC的代码以及使用这些MOC的代码。

我真诚地怀疑,如果与当前上下文无关,那么运行循环处理实际上是否会在商店上获得一个锁,因此,可能与后台MOC发生了一些隐藏的交互。我敢打赌,您的应用程序中仍然存在某些东西,您认为自己没有这样做,这在某种程度上使后台工作与主MOC交叉了。

如果需要,可以轻松跟踪[_PFManagedObjectReferenceQueue _processReferenceQueue:]的调用方式。

测试1. 创建一个简单项目,选中Core Data框以获取一个简单的Core Data模板项目。在_processReferenceQueue:处放置一个断点只是为了确保您可以获取该断点。

测试2。注释掉实例化核心数据的部分,并查看是否仅通过链接到框架即可达到断点。

测试3. 创建MOC,但不要对其进行任何其他操作。只需创建它。重复查看是否达到断点。

测试4。摆脱“默认MOC”,基本上就像测试2。现在,创建一个私有(private)队列MOC,并通过performBlock与它进行简单的交易,看看是否达到断点。

您可以看到前进的方向。基本上,确定非常简单的用例的哪种组合会导致您在主线程中达到断点

至少,这将让您知道框架本身是否/何时导致这种情况发生,这反过来又应该使您了解您的复杂应用程序在做什么。

编辑

好奇心使我变得更好。我只是运行了一些简单的测试,在这两个位置都设置了断点:
-[NSManagedObjectContext(_NSInternalAdditions) lockObjectStore]
-[_PFManagedObjectReferenceQueue _processReferenceQueue:]

除非我实际上与MOC发生冲突,否则我看不到任何打击。每个MOC都是限制并发类型。我创建了一个具有100,000个简单实体的数据库。

主线程使用FRC加载数据。我添加了一个按钮,按下该按钮将启动dispatch_async并获取所有100,000个对象。

我看到两个断点都在辅助线程中命中,但是都没有在主线程中命中。当然,如果我在主线程上获取或更新了MOC,我会遇到这些断点。

我正在模拟器上运行。

因此,我的结论是,CoreData本身不应对您看到的行为负责。

可能是由于MOC上的某些配置,持久性存储协调器,持久性存储或上下文之间的某些未知交互。

没有关于对象和实际代码的配置的进一步信息,我的最佳结论是,您正在代码中执行“某些操作”以使这种情况发生。

您应该设置这些断点,并查看当它们被击中时代码中正在发生的事情。

关于iphone - 主线程在执行后台线程时正在等待[NSManagedObjectContext(_NSInternalAdditions)lockObjectStore],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12168761/

有关iphone - 主线程在执行后台线程时正在等待[NSManagedObjectContext(_NSInternalAdditions)lockObjectStore]的更多相关文章

  1. ruby-openid:执行发现时未设置@socket - 2

    我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass

  2. ruby - Chef 执行非顺序配方 - 2

    我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul

  3. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  4. ruby - 为什么 Ruby 的 each 迭代器先执行? - 2

    我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试

  5. ruby - 检查是否通过 require 执行或导入了 Ruby 程序 - 2

    如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby​​文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否

  6. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  7. ruby-on-rails - rbenv:从 RVM 移动到 rbenv 后,在 Jenkins 执行 shell 中找不到命令 - 2

    我从Ubuntu服务器上的RVM转移到rbenv。当我使用RVM时,使用bundle没有问题。转移到rbenv后,我在Jenkins的执行shell中收到“找不到命令”错误。我内爆并删除了RVM,并从~/.bashrc'中删除了所有与RVM相关的行。使用后我仍然收到此错误:rvmimploderm~/.rvm-rfrm~/.rvmrcgeminstallbundlerecho'exportPATH="$HOME/.rbenv/bin:$PATH"'>>~/.bashrcecho'eval"$(rbenvinit-)"'>>~/.bashrc.~/.bashrcrbenvversions

  8. ruby - 如何让Ruby捕获线程中的语法错误 - 2

    我正在尝试使用ruby​​编写一个双线程客户端,一个线程从套接字读取数据并将其打印出来,另一个线程读取本地数据并将其发送到远程服务器。我发现的问题是Ruby似乎无法捕获线程内的错误,这是一个示例:#!/usr/bin/rubyThread.new{loop{$stdout.puts"hi"abc.putsefsleep1}}loop{sleep1}显然,如果我在线程外键入abc.putsef,代码将永远不会运行,因为Ruby将报告“undefinedvariableabc”。但是,如果它在一个线程内,则没有错误报告。我的问题是,如何让Ruby捕获这样的错误?或者至少,报告线程中的错误?

  9. ruby - 如何在 ruby​​ 中运行后台线程? - 2

    我是ruby​​的新手,我认为重新构建一个我用C#编写的简单聊天程序是个好主意。我正在使用Ruby2.0.0MRI(Matz的Ruby实现)。问题是我想在服务器运行时为简单的服务器命令提供I/O。这是从示例中获取的服务器。我添加了使用gets()获取输入的命令方法。我希望此方法在后台作为线程运行,但该线程正在阻塞另一个线程。require'socket'#Getsocketsfromstdlibserver=TCPServer.open(2000)#Sockettolistenonport2000defcommandsx=1whilex==1exitProgram=gets.chomp

  10. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

随机推荐