Re: drawing in a separate thread
Re: drawing in a separate thread
- Subject: Re: drawing in a separate thread
- From: Graham Cox <email@hidden>
- Date: Sat, 3 May 2008 14:51:10 +1000
On 3 May 2008, at 1:40 pm, Duncan wrote:
On May 2, 2008, at 12:49 PM, Graham Cox <email@hidden>
wrote:
Subject: Re: drawing in a separate thread
OK, I have managed to implement this after a lot of poring over the
docs. I'm not sure if it's the most efficient way to actually
handle the thread communication, but it does work (using
NSMachPort). As I hoped, there isn't a big problem with drawing the
graphics as they should be, apart from a bit of occasional blank
output when the window is resized - BUT, performance is terrible.
Worse than synchronous drawing by a long shot - I haven't measured
it because it's really obvious how much the drawing lags the user -
must be an order of magnitude slower.
Question is of course, why? The thread is calling the exact same
drawing code as the view normally does, so that's a constant. So it
must be down to the thread communication/overhead. Or perhaps just
my minimal understanding of threads, locks, ports etc. ;-)
When I need to draw, I flag that fact to the class (the class is
handling all views using a single secondary thread, but in fact I
only have tried it so far with one), and the class bundles the
update rect and view into an NSInvocation, which is placed in a
queue. An NSPortMessage is used to wake up the thread which pulls
the invocation off the queue and invokes it, which does the
drawing. Maybe the use of NSInvocation is slow? Not sure why it
should be.
I think using DO IS overkill, and has too much overhead for your
application.
I agree ;-)
I've used a fairly lightweight model for worker threads. I used a
variation of ThreadSafeQueue, and created a job queue. I then
created one or more worker threads that looks in the queue for work
to do. When the thread finds work, it does the work, then blocks on
a condition lock until there is more work. It works beautifully, and
without much overhead.
In your case you'd probably only have one worker thread, and let
that thread handle all your time-consuming drawing.
See this link for info on the ThreadSafeQueue class: http://www.cocoadev.com/index.pl?ProducersAndConsumerModel
Looks ideal, thanks for the link.
One thing I realised after the previous posting is that the
performance hit I'm seeing is because unlike the usual drawRect: case,
I wasn't doing any clipping to the update area, so the entire view was
getting repainted rather than just some small part of it - adding a
clipRect: call substantially improved things.
However it also made me realise that just doing the drawing on a
second thread is not enough - my graphics code makes quite a bit of
use of the view's -needsToDrawRect: method, which of course when it's
called by the thread is just not going to be valid, as drawRect: has
been and gone. I'm not sure how to tackle this - it would seem I'd
have to cache the result of -getRectsBeingDrawn:count: each time I
queue a draw from the main thread and somehow make these rects
available to clients of the view when they are drawn from the second
thread (by overriding needsToDrawRect: for example). This seems
complicated and somewhat hackish - or I redesign the drawing code to
have these rects passed down as a parameter for every draw, which is
equally awkward.
I'm not yet convinced that drawing on a second thread will really give
any benefit, so I'm reluctant to change things dramatically to allow
it when I may end up abandoning the whole idea.
Be useful to hear from anyone who's done something like this to a)
convince me it's worth it and b) hear about any solutions to the
update rects issue.
tia,
G.
_______________________________________________
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