Xojo 2020 R2 introduced the Worker class. The Worker is Xojo’s way to use more cores and process data faster. This is important because the Xojo thread class is cooperative meaning that it runs on the main thread, the same one as your application, and thus shares processor time of a single core.
Why do we use threads in the first place? Generally it’s to do a lengthy process and you don’t want the user interface to lock up. There’s nothing more irritating from a user perspective than to have your app do nothing for a few minutes as it chugs through something. Threads prevent this but there’s a tradeoff using them because it means the overall time it takes to do the processing is longer. So while the app remains responsive to the user it takes longer for the processing to complete.
So the Worker class is Xojo’s attempt at multi-processing. The Worker class actually creates a console application that is placed in the application bundle/package and handles all the work of spawning the process and passing information back and forth.
I spent some time this week banging on the two Xojo Worker examples in both Mac and Windows and found some mixed and complex results. My quick and dirty response about Workers and how good they are is: ‘it depends’. Let’s start talking about the examples.
My first attempt was taking the Xojo example project PictureResizer and taking it through its paces. I tested a folder with 1071 png and jpg files. In all tests I used compiled applications because attempting this in debug results in the Workers using threads (more on this later). For my workers I allowed 4 cores and up to 90% core usage to stress it out. I used my 2015 MacBookPro that’s been BootCamped to use the exact same hardware. MacOS side is using Catalina and Windows is using Windows 10 64-bit.
My initial results were this:
Mac: 274 seconds
Win: 115 seconds
My first question was why Windows was so much faster. So instead of using Picture.Open I switched to reading the file in via BinaryStream and then using Picture.FromData.
Mac: 182 seconds
Win: 106 seconds
Better but still quite a bit different. I suspect that Mac console apps are using a much slower Picture library than desktop. So I then created a thread (using default settings) and found the following:
Mac Picture.Open: 196 seconds
Mac Binary Stream: 200 seconds
Win Picture.Open: 124 seconds
Win Binary Stream: 205 seconds
I find it surprising that Picture.Open is considerably faster on Windows than Mac. But I was still not satisfied with this result as it seems like Workers aren’t working as expected (pun intended). So I created a new version and passed in 20 files at a time to the Worker.
Mac Picture.Open: 196 seconds
Mac Binary Stream: 176 seconds
Win Picture.Open: 115 seconds (no difference)
Win Binary Stream: 106 seconds (no difference)
So this says to me that the example is flawed. Only processing one picture at a time isn’t very efficient. There is some overhead to start a Xojo console application and it seems that on macOS it’s significant enough to barely make it better than using a thread.
For test two I took the WordCount example and modified it to be able to do the same processing from a thread as well as the Worker. I also decided to test this without using any background process just for comparison sake. I used 1320 Text files of random length. Test results:
Worker: 13.41 seconds
Thread: 35.53 seconds
No Thread: 34.85 seconds
Worker: 19.09 seconds
Thread: 20.04 seconds
No Thread: 25.79 seconds
I think this example is a bit better since there is a ton of string processing that obviously takes a while. On macOS you can see that the Worker is clearly better than the Thread and even the no thread. In Windows there is not much difference and I’m not sure how to explain this difference other than that maybe starting new processes in Windows is slow but still it’s obvious that Workers are better than no thread and slightly better than using the Thread. With something that requires even more work I would expect this to be more pronounced.
One of the beefs I have with Workers is that you literally cannot test them in the debug environment. When you test in the debugger you’re really working in a thread. One of the strengths of Xojo is that working in the debugger is mostly the same as working in the real thing and Workers break that paradigm. It’s a shame but maybe Xojo can fix this in a future release.
My other take away from using Workers is that it’s not a panacea for everything just like using Threads is not perfect. Workers are Xojo console applications and there is overhead to starting them. Xojo does make them easy to use by handling the inter application communications but with only string processing available you might be better off using IPCSocket communication but that’s not without its tradeoffs too.
Using Workers will take some work on your part to make sure you’re doing it as efficiently as possible. Is it better to process a number of things in the Worker or do them one at a time? And of course if you decide on Workers you’ll have more ‘joy’ in testing them. Overall, ‘it depends’ on your needs to know if Workers are useful for your application.