Is it sensible to start `CLLocationManager` on a background thread?
Asked Answered
S

1

7

According to the documentation of CLLocationManagerDelegate

The methods of your delegate object are called from the thread in which you started the corresponding location services. That thread must itself have an active run loop, like the one found in your application’s main thread.

I am not clear as to whether this means that to receive location manager updates on a background thread, we must instantiate the location manager on that background thread or simply call the startUpdatingLocation() method on that thread.

In any event, this explains an issue when a CLLocationManagerDelegate does not receive any events from a CLLocationManager which was started on a background thread:

That thread must itself have an active run loop

If I understand run loop functioning correctly, all NSThreads are instantiated with a run loop, but the run loop will only be running if you assign some work to the thread. Therefore, to have a CLLocationManager send events correctly on a background thread, we need to set the thread's run loop to loop permanently so that it can process the CLLocationManager's calls as they arrive.

A reasonable solution to making sure the run loop is running is suggested in this question but the author implies that this is a processor expensive way of doing it.

Also, according to the threading documentation,

Threading has a real cost to your program (and the system) in terms of memory use and performance

I appreciate that we are all using lots of threading anyway, by using Grand Central Dispatch, but Grand Central Dispatch probably mitigates a lot of this in its internal thread management.

So my first question is, is it worthwhile setting up a background thread with a continuously running run loop, in order to have location events dealt with on a background thread, or will this involve an unreasonable extra amount of processing when compared to leaving the manager on the main thread?

Secondly, if it is worthwhile, is there a good way to do this using Grand Central Dispatch. As I understand the documentation, Grand Central Dispatch manages its own threads and we have no means of knowing which thread a given block will be executed on. I presume we could simply execute the usual run loop code to make the run loop of whichever thread our CLLocationManager instantiation is run on loop continuously, but might this not then affect other tasks independently assigned to Grand Central Dispatch?

Selfgovernment answered 28/4, 2017 at 16:38 Comment(0)
S
10

This is a somewhat opinion-based question, but I have a pretty strong opinion on it :D

No.

Just deliver the events to the main queue, and dispatch any work to a background queue if it's non-trivial. Anything else is a lot of complexity for little benefit. CLLocationManager pre-dates GCD, so this was useful information in the days when we occasionally managed run loops by hand and dispatching from one thread to another was a pain. GCD gets rid of most of that, and is absolutely the tool you should use for this. Just let GCD handle it with dispatch_async.

You absolutely should not set up your own NSThread for this kind of thing. They're still necessary at times for interacting with C++, but generally if GCD can handle something, you should let it, and avoid NSThread as much as possible.

Shrieve answered 28/4, 2017 at 16:54 Comment(5)
Thanks for the reply Rob! Apart from the additional complexity, do you know if the performance implications of setting up the background NSThread with a continuous run loop are likely to outweigh the performance implications of receiving events on the main thread before dispatching them using GCD?Selfgovernment
What performance implications are you thinking? Are you thinking processing a few extra messages a second at most (generally less) on the main queue and immediately calling dispatch_async is going to overwhelm the main queue? I would definitely wait until you demonstrate a problem in Instruments. I wouldn't assume that NSThread is cheaper. Threads are expensive in both memory and due to context switching, which is horrible for performance.Shrieve
This is kind of what I was thinking, but wanted confirmation from someone more knowledgable than myself! However, wouldn't dispatching immediately from the main thread via GCD also involve context switching etc, since GCD will itself be using threads?Selfgovernment
In some cases, eventually. GCD tries to optimize this, so you don't know. But trying to optimize it before profiling an actual piece of software is not useful, and is likely to backfire. Keep the system simple. Personally, I manage most CLLocationManager responses entirely on the main queue, unless they're very complicated. That prevents lock contention when I have to modify data structures. I've had to move them before, but I don't do that as a default position.Shrieve
(I started in Cocoa before GCD. I used to write entire OS X programs on a single thread for a single-core 1GHz G4. There's a lot expected of modern apps, but I folks often forget just how much a modern processor can handle. Not everything; performance absolutely matters, but we often fret in the wrong places.)Shrieve

© 2022 - 2024 — McMap. All rights reserved.