Re: Threads and Core Data, bindings results in view corruption
Re: Threads and Core Data, bindings results in view corruption
- Subject: Re: Threads and Core Data, bindings results in view corruption
- From: Ben Trumbull <email@hidden>
- Date: Mon, 31 Mar 2008 20:51:08 -0700
At 1:49 PM -0400 3/31/08, David wrote:
I'm relatively new to Cocoa.
Welcome.
From my previous work in win32 and Java this is the normal scenario,
not an unusual one. Can someone point me to some sample code that
illustrates how to have a worker thread updating data which is
displayed in the UI?
There's a Background Fetching example in /Developer/Examples/CoreData/
You can file bugs against the doc, and Core Data, and for a better
example. File early, file often.
In the meantime, the list is a great place to ask questions.
In my case I am/was trying to maintain a outline view representing
files, storing each node in core data. Based on these responses I'm
not sure what technologies I should reasonably be using. Is this too
fine grained for Core Data? Should I give up on bindings? Should I
give up on NSTreeController?
If you're on 10.5, I definitely would not give up on Bindings and the
tree controller. It's my understanding there are issues with the
tree controller on 10.4. Bindings is a bit outside my area of
expertise, so I recommend googling about the tree controller on 10.4.
I vaguely recall Jonathan writing up something about this on
<http://rentzsch.com/>
As for Core Data, I recommend you change your store to SQLite (1
line) and see where that puts you.
If you're still having trouble with this, and you should really file
a bug report, and attach a Shark sample, and we'll see if we can
identify some improvements for you to use.
One reason to file bugs is, occasionally, you'll get a nice work
arounds back from Apple Developer Relations and continue on your
merry way.
In contrast, some developers have needlessly tormented themselves,
say trying to use GC, without asking any questions on the list or
filing bugs for many months.
If I try to maintain multiple MOCs, that means I have to save to get
it to show up in the other moc, right?
Yes. I'd ask the controller via -performSelectorOnMainThread:
The save as binary file can take 15 seconds in my case when I have
thousands of nodes.
That's bad. Use an sqlite store instead. First, even without
threads, it'll handle thousands of nodes MUCH better. Faster,
smaller, goodness all around.
Secondly, with multiple threads you can get up to 29,000 inserts per
second going.
That hangs the UI longer than adding the nodes to start with.
Should I try to use a in memory persistent store or will that still
be slow or cause an excessive memory penalty?
Try the sqlite store first, and then get back to us.
Can I ask why don't bindings lock the bound MOC or provide the
option to? I had assumed (incorrectly) that bindings would handle
threads OR provide some means to control or configure its threading
behavior.
As far as I know, Bindings does not under any circumstances, and
that, basically your view objects are all pinned to the main thread.
I believe all the view and controller classes are fundamentally
designed around NSRunloop.
File bugs. Telling me doesn't help, because this is outside my area.
To be fair to Bindings, I don't think locking the MOC is a great
solution. Background threads could starve the main/UI thread which
would be bad. Fixing Core Data so you didn't have to save before
passing objectIDs to the UI's MOC seems a much better idea, imo.
Why doesn't core data support locking at a finer grain? Or to
rephrase, it would be very helpful if Core Data could lock at a
ManagedObject level.
There lies dragons. Fine grained locking doesn't work.
Start here and get back to me:
(0) <http://lists.apple.com/archives/cocoa-dev/2007/Mar/msg00739.html>
(1) a great article by Edward Lee from UC Berkeley. The canonical
"why threads suck" and what we could do about it article.
<http://www.computer.org/portal/site/computer/menuitem.5d61c1d591162e4b0ef1bd108bcd45f3/index.jsp?path=computer/homepage/0506&file=cover.xml&xsl=article.xsl>
(2) Article on serious performance optimizations for multicore
machines. It discusses several practical techniques like lock
striping that ObjC and CF now use:
<http://developers.sun.com/learning/javaoneonline/2006/coolstuff/TS-5354.pdf>
(3) "Java Concurrency in Practice" The first really good book about
multi-threading *engineering* instead of theory or APIs
<http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1206565296&sr=8-1>
(4) "Pattern Language for Parallel Programming" Basically, the Gang
of 4 design patterns book, done for parallel programming. Not quite
as good as "Design Patterns" (which you're crazy if you haven't yet
read), but then, what is ?
<http://www.amazon.com/Patterns-Parallel-Programming-Software/dp/0321228111/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1206565387&sr=1-1>
I expected there to be a locking or transaction mode where I can
lock it while I fill in an object. Nothing else should require me to
worry about core data getting corrupted with multiple threads.
Sounds like a feature request you should file. There are better ways
to implement this than locking at the NSManagedObject level.
I have interpreted that to mean that locking the
managedObjectContext would be sufficient. I hadn't realized that
bindings would try to obtain locks.
No, it doesn't. But it needs to obtain locks to honor your locking.
The list archives also have these, which you should read:
<<http://lists.apple.com/archives/cocoa-dev/2007/May/msg00222.html>http://lists.apple.com/archives/cocoa-dev/2007/May/msg00222.html>
<<http://lists.apple.com/archives/cocoa-dev/2008/Jan/msg01889.html>http://lists.apple.com/archives/cocoa-dev/2008/Jan/msg01889.html>
It's possible to shuttle pending changes between threads by hand using KVC.
Are you describing in general or specifically with Core Data? Can
you give more insight on this? Are you saying that I manually track
changes from core data?
For updates objects, you can just pass a dictionary of deltas between
threads if you don't want to save.
For inserted objects, you'd need a proxy insert. But, yes this works
generally and with Core Data (although not conveniently).
Both KVC and Core Data have methods to make this somewhat less painful.
Manually tracking changes from Core Data is pretty easy. We post the
NSManagedObjectContextObjectsDidChangeNotification every time you
call -processPendingChanges.
On Leopard, in the scenarios under which you can save, you can also
use -mergeChangesFromContextDidSaveNotification:
But isn't a notification received on the same thread on which it was posted?
Yes, but that's not what the API is for. It takes the notification
object, and merges it into the current MOC's state.
You could grab the notification object from the save on your
background thread, and pass it to the main thread with
-performSelectorOnMainThread: and this method will merge all the
changes into the main thread's MOC.
It still requires inserts be saved, but otherwise handles all the
merging logic efficiently.
Finally, in 4 years no one has filed a bug about this.
File a bug about what?
Everything you don't like. Documentation, example code, Core Data,
Bindings, performance, enhancements, feature requests ...
Do you consider the threading behavior in bindings and Core data to be a bug?
This is about what you consider to be suboptimal.
--
-Ben
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden