Reputation: 6679
I have three tasks:
A fetch task. It fetches objects (around 2000 of them) from CoreData
and passes the NSManagedObjectIDs
to the main thread where they're converted back to NSManagedObjects
and stored in an NSArray
. This task is of least priority.
A computation task. This task iterates through those objects and calculates some values for the object. The values are stored as transient attributes of the NSManagedObject
subclass. This task is the 2nd highest priority.
An OpenGL ES Drawing Task. This is the drawing loop that updates the UI based on the result of the computation task. This task is highest priority as any slow down will decrease the frame rate and be very apparent when zooming or panning.
My issue has been creating a design pattern that allows the first two tasks to do their work while still allowing the OpenGL task to run at maximum frame rate. What inevitably happens if I use GCD queues is that the OpenGL task will be blocked by one of the other two and it will stutter.
I'm thinking that I need to have the OpenGL thread operate on it's own copy of the data, but I'm not sure what that looks like or even if it's the correct solution. Has anyone dealt with this type of issue before? If so, how did you achieve both concurrency and performance?
Upvotes: 2
Views: 916
Reputation: 6679
For those who find this thread at a later point, here's how I eventually solved the issue:
The fetch task runs in it's own GCD queue and fetches the NSManagedObjects from CoreData. I created a new class that contains the computed properties for each of my objects. Using the fetched data, I instantiated an NSArray of these objects and passed them on to the compute task by dispatching a block operation in the compute queue.
The compute task runs in it's own GCD queue and computes the values for each of these objects every second or two. After it's finished, it passes on the NSArray to the drawing queue by dispatching a block in the drawing queue.
The drawing task runs in it's own GCD queue and is asynchronous. All it does is loop through the objects and draws them.
Basically, when one queue is finished operating on it's data, it passes the data onto the next queue by dispatching a block in that queue. This prevents race conditions and solved the design pattern issues I was having. The only downside to this approach is that it does require a bit more memory. In my tests however, after a few optimizations, the memory usage is not all that bloated. Thanks to the various community inputs as I stumbled through this.
Upvotes: 1
Reputation: 13999
I think the best solution is the following.
Please refer to the document "OpenGL ES Programming Guide for iOS - Concurrency and OpenGL ES"
Identifying Whether an OpenGL Application Can Benefit from Concurrency
The application performs many tasks on the CPU that are independent of OpenGL ES rendering. Games, for example, simulate the game world, calculate artificial intelligence from computer-controlled opponents, and play sound. You can exploit parallelism in this scenario because many of these tasks are not dependent on your OpenGL ES drawing code.
Still, if you need to use Multi-threaded OpenGL ES rendering, these useful documents may help you.
Upvotes: 2