There was an annoying bug in my RomyView application the other day, a bug that caused what is in my mind, the worst kind of situation when it comes to asynchronous code: My code that populates a thumbnail cache item (which gets the image from the Windows Shell for .jpg files and movie files, and creates it directly for .png files and icons) was running on the main thread. Disaster! This happened, of course, while populating thousands of thumbnails, and brought the entire application to a grinding halt.
So just for the hell of it, I googled “Async in C# 5” and sure enough, I found a copy of the book for free. I guess I shouldn’t admit that. Sorry! Anyway, to my surprise, there is very little in that book that I do not already know. Very little. Purchasing it would have felt like a waste of money.
Update: I decided to buy the e-book instead. I did only browse through it in a couple of minutes, and clearly a lot of work went into the book. It’s only $9.99 on the O’Reilly site, which works out cheaper than buying the e-book on a South African site.
It turns that I am running an overload of Task.Factory.StartNew that takes TaskCreationOptions and a TaskScheduler as parameters in the offending method. The TaskCreationOptions parameter needed to change to TaskCreationOptions.LongRunning to force the underlying thread to run on the thread pool.
I have also been playing around with different TaskScheduler implementations to see which is most performant for this purpose. But it feels a little like stumbling around in the dark. I am using several different schedulers in the application, and while I understand each one in itself, I do not understand how all of them relate to each other in the overall application. That is, if I have three levels of priority in a queued scheduler that’s running on the IO threadpool, but also have some code retrieving thumbnails via a round-robin scheduler, and some threads fighting over populating the thumbnails via a work-stealing scheduler, which scheduler runs when?
I was hoping the book might lead me to the light… but it did not. All I can say is, to anyone else running similar code, do not have all your code run in queued schedulers, because you will be sure to run into issues when code that you would like to run now is not in the front of the queue.
So far, at least in my experience, work-stealing schedulers are generally the better way to go, and for each discrete task being performed, having its own dedicated scheduler seems preferred. But don’t listen to me. I’m making it up as I go along.