Search code examples
multithreadingdesign-patternsgrand-central-dispatchswift5

Simplest way to switch context back and forth (dispatching)


I have two classes that perform independent computation. For the sake of simplicity here, I will represent them with functionscalc1 and calc2. At some random places in each function, I need to sleep for a while. Rather than doing calc1 and then calc2, I'd like to switch back and forth between them.

I could use threads, but it seems to me at first sight overly engineered to do so. In addition, these 2 functions need to be on the main thread, because they deal with user interface. I do not need different threads. I just need to switch from one context to another, and back where we were.

In python, there is the concept of greenlet (gevent) which allow simple context switching, without being real thread. That would be perfect for my need. Is there such a mechanism in swift ?

func calc1() {
...
sleep(300) // go to calc2
...
}

func calc2() {
...
sleep(200) // resume calc1
...
}

Solution

  • This notion of alternatively switching between two computationally expensive calculations on the main thread is not going to work.

    • First, we never do anything computationally expensive on the main thread. We should never block the main thread for any reason. It results in a horrible UX (your app may appear to frozen) and you risk having the app killed by the OS watchdog process (which is looking for apps that appear to be frozen and are blocking the main thread).

    • Second, if calculating two truly independent calculations, we wouldn't add the overhead and complexity of trying to switch between them. We would just use GCD to dispatch them independently to background queue(s).

    So, the solution for this sort of process would be to dispatch these two tasks to run concurrently on background queue(s), either to one concurrent queue or two dedicated queues. But the key is to perform the complicated calculations off of the main thread, in parallel, and then dispatch the periodic UI updates back to the main thread. But always keep the main thread free to respond to user input, system events, etc.

    FWIW, this process of dispatching these two independent tasks separately is simpler and a far more efficient use of the device resources. Just synchronize updates to model objects. And dispatch groups are a great way to keep track of when two independent concurrent tasks finish.