Very recently I needed to improve the generation tens of thousands of images with a Xojo Desktop project. The image generation code had already been written, and takes advantage of several desktop specific features (custom font activation with MBS most specifically).
The process took minutes originally. It was so bad that the initial author of the code stuck a confirmation dialog to the user prior to running the batch. Now, because of the world events, the batches were larger than ever. On a whole it had to be improved.
Obviously the best way to speed this up was to split the batch into chunks for helper processes. This was going to be a new adventure in Xojo for me, and I was ready to take a bite.
Launch a copy of the main app but with parameters to run as helper! The master process will need a thread to manage the spawned helpers. This thread will need to calculate all the images to be generated, split them up into batches, launch , and then track the helpers.
App arguments aren’t normally available in the App.Opening event of a Desktop project, but thanks to MBS they can be. The first check will be for the arguments we’re expecting. If passed, instead of showing the main UI, process a batch of images as directed. Finally the app will quit when the thread is finished to signal completion of the batch.
It sounds simple, but it gets tricky…
We know these processes will take a long time. Normally not an issue, but these are Desktop apps. If the main thread is locked up in a loop with image generation, the UI will become “not responding”. Windows will alert the user after a few seconds and we can’t have that. The user doesn’t even know the app is running.
To keep the UI (that is not visible) responding the image generation loop must be threaded. Think about debugging this nightmare. We are now in a runtime instance thread, of a helper app launched by a shell command running in a thread of another process. To top it all off, the IDE can only connect to one instance of an app name at any time.
Debug Command Line Arguments come in handy here. Unfortunately, I couldn’t come up with a nifty way to automate the whole thing; but I did design it so that in debug mode, the testing command line arguments are written for me. The trick is that when these parameters are present, it is possible to debug the inner most incepti-thread.
As each helper app works, the master app monitors and relays status to the user. With a carefully coordinated filesystem dance, the processes don’t need to pass any image data between each other. When all of the shells have completed, the master thread pulls everything together. Some final cleanup occurs, and the master thread completes.
In the end, it all works! The client is pleased as this minutes long process is now tolerable and on average 4x faster. I’m really pleased that it all worked out as planned. If you have some hours to experiment, it’s a really fun (and tough) puzzle to crack.
I’m here if you need me 🙂