2

I have made a rather complex .NET 4.0 (C#) Windows Forms application using Visual Studio 2013. The question is quite general though, and should be applicable for other versions of .NET and VS as well.

On startup the system reads config file, parses file folders and reads file content, reads data from database, performs a web request and adds data to a lot of controls on the main startup form.

I want to avoid having a splash screen with "waiting-hourglass", the goal is to make the application startup fast and show the main form immediately.

My solution has been to use backgroundworker for some of the startup tasks, making the application visible and responsive while data are fetched. The user can then choose to navigate away from the startup form and start doing other tasks without having to wait for all the startup procedures to be completed.

Is use of backgroundworker suitable for this?

What other methods should be considered instead of, or in addition to, backgroundworker to enable fast startup for an application with a lot of startup procedures?

  • 2
    You might also want to take a look at the Native Image Generator if you're not already familiar with it. https://msdn.microsoft.com/en-us/library/6t9t5wcf(v=vs.110).aspx – bmt22033 Jan 08 '16 at 14:13
  • Thanks' for the tips, not familiar with Native Image Generator, will look at it. Anyone with experience using it? Is is complex? Any pitfalls? – Kjell Inge Hestad Jan 08 '16 at 14:32
  • 1
    Don`t think your application will benefit from NGEN. Precompilation will reduce startup overheads related with JIT compilation. This is not your primary concern here. You will need to optimize and sideload components after your application is executed. – Marc Wittmann Jan 08 '16 at 14:47

3 Answers3

3

In my applications I use a splash screen. However, I do not show a waiting-hourglass. Instead it shows a status line where current action is written, e.g. "Read config file", "Connect to database", "Perform web request", etc.

Of course, the application does not start faster but the user does not have the feeling of a hanging program and it appears faster.

Wernfried Domscheit
  • 54,457
  • 9
  • 76
  • 110
  • Doing these is still better to be done on a separate thread to avoid the splash screen becoming a ghost window if any of the operations takes a long time to complete. – Balázs Jan 08 '16 at 14:12
  • Absolutely a good solution, but it still makes the user have to wait for the process to finish. My system parses a file folder and reads content, that can take up to one minute for users with low-end PC's. That is to long time to wait, so it has to be done in the background ^_^ – Kjell Inge Hestad Jan 08 '16 at 14:21
  • +1 for usability suggestion. This won't make application faster but it won't annoy user when she knows what's going on? – vendettamit Jan 08 '16 at 14:22
  • @KjellIngeHestad If you are using Bg worker to load data async way.. would you allow user to interact with partially loaded screen? May be No. Situation will remain same. So you need to think of many things while optimizing the app startup time. – vendettamit Jan 08 '16 at 14:24
  • I assume the major problem is: usually at startup most of the tasks have to run in certain order, only a few can run independently at any time. The Backgroudworker does not help so much in such situation. – Wernfried Domscheit Jan 08 '16 at 14:34
  • @vendettamit you can still programmatically disable controls while keeping your app responsive. – Balázs Jan 08 '16 at 14:35
  • @vendenttamit the startup screen is actually some kind of dashboard with status info, but with some possibilities to do timespan selections. So for me: yes - for this form I would like the user to see and interact with a partally loaded screen, or just leave the screen before it is fully loaded, instead of keeping the user waiting for the screen to be complete. I can see that for some forms this would not be usable, typically if the user should be able to edit content. – Kjell Inge Hestad Jan 08 '16 at 14:37
  • @WernfriedDomscheit this is not always the case. Also, the point of delegating some processing to separate threads is more often than not because of IO-bound operations. For example, waiting for data from a WS over a slow network, reading data from a slow disk, etc. Doing these on a separate thread is only to prevent the main thread from becoming busy. When everything is loaded, you can just "merge" the data on the main thread. This sounds like a CPU-bound operation, in which case using separate threads won't help you at all. – Balázs Jan 08 '16 at 14:39
  • 2
    @vendettamit You are correct, most of the tasks in the backgroudworker runs in a spesific order. The most important benefit using the backgroudworker is that the user can interact with the application wile the process runs in the background. I have deactivated some menu items and controls while it is running to avoid user to do some tasks, like it is not possible to go to application settings befor the settings are read from the config file. – Kjell Inge Hestad Jan 08 '16 at 14:40
  • Yup That's what I was talking about. +1 – vendettamit Jan 08 '16 at 14:48
2

In any case it depends if early access availablity makes sense for the user. A good way would also be to just preload the first page / form / tab before the user can see the interface (Splashscreen or loading bar before that).

When the first bits are loaded you could asynchroniously cache more data and only allow the user switching pages / tabs when the caching of these components is completed (you will have to display a "still loading" message or grey out other tabs while doing this to not confuse the user). You can also just load addditional data if the user chooses to use the page / tab / feature to reduce loading unneccesary information but this will lead to waiting while using the application - it`s up to you.

Technically, as BackgroundWorker is explicitly labeled as obsolete in .NET 4.5 you should see if the introduced await/async would be a more elegant solution for you (See MSDN Asynchronous Programming with Async and Await Introduction)

MSDN says:

The async-based approach to asynchronous programming is preferable to existing approaches in almost every case. In particular, this approach is better than BackgroundWorker for IO-bound operations because the code is simpler and you don't have to guard against race conditions.

See a comparison thread Background Worker vs Await/Async

See a well commented example of backgroundworker code to load GUI data if you choose to use that technique

Liam
  • 27,717
  • 28
  • 128
  • 190
Marc Wittmann
  • 2,286
  • 2
  • 28
  • 41
  • Thanks' for a very complete and thorough advice. To be compatible with Windows XP I have sticked to .NET 4.0 for now - close to 5000 users so far and a lot from east-europe and some from russia, and in these regions Win XP is still in use. I will anyway take a look at "Async and Await" and plan for replacing use of backgroundworker. – Kjell Inge Hestad Jan 09 '16 at 14:41
  • Even though other answers also gave useful info, do I feel this was the most complete and with most informative answer so far. – Kjell Inge Hestad Jan 09 '16 at 14:46
1

Rather an advice than an answer:

  • Is use of backgroundworker suitable for this? - yes.

  • What other methods should be considered instead of, or in addition to, backgroundworker to enable fast startup for an application with a lot of startup procedures? - consider on-demand a.k.a. lazy loading of data. That is, load the data only when they are actually needed rather than query everything at once possibly many of them without ever being used or looked at. If this is not possible as of your UI setup, consider refining your UI and rethink whether everything should be displayed as is. For example, use separate windows or expanders to display details and query the data when they are made visible. This does not only save you time on app startup but also makes sure that you display any data in an up-to-date manner.

Balázs
  • 2,929
  • 2
  • 19
  • 34
  • Thanks for the feedback, I do actually load some data and stores it in memory (datatables) on startup to make the application more responsive when using it later on. Will look at this and consider moving this to the first time the data is actually needed, might save some initial loading time - but will then again make the first time operation slower when the data is needed. It will be a trade-off i guess. – Kjell Inge Hestad Jan 08 '16 at 14:27
  • Accessing the data for the first time will indeed be slower but you avoid loading data that the user may not even use. Also having to wait more times but for shorter periods probably makes your app feel more "fluid". I wouldn't really call it a tradeoff as you don't actually sacrifice anything, you just slice up the time taken by waiting. – Balázs Jan 08 '16 at 14:34