Last week I helped a colleague who was experiencing UnobservedTaskExceptions I his code. The problem was essentially that the code started several tasks and then in a loop checked each one if it was faulted or not. If a task was faulted the method threw an exception. This meant that if two tasks faulted in the collection of tasks then the second one was never observed causing an UnobservedTaskException that brought down the process. While this sounds simple it turned out to be a hard nut to crack for a number of reasons.
First of all you need to know some things about the UnobservedTaskExceptions; while they by default crash your process in .Net 4.0, they don't in .Net 4.5. The fun thing is that you get the 4.5 behavior on your 4.0 assemblies by just having 4.5 installed. There is a way to configure your application to use the old 4.0 behavior and you can read about that and why the default behavior changed here. Forgetting this can frustrate you if your build environment does not have 4.5 but you have it on your own machine.
Second you have to remember that even if you use async/await you can still end up writing code that have the same "problem". The "problem" is that you only bubble up the first error you see and not all errors. For many reasons I think this is what you actually want (WhenAllOrError anybody?) but if you really want to get all exceptions you can just use Task.WhenAll and you'll be good.
I read this interesting article that illustrated the difference between processes optimized for flow efficiency versus resource efficiency. Maybe not obvious in that article why flow is cheaper (or same) cost as resource optimized but if we assume customer satisfaction is a great asset I think it is obvious which process is preferably from a customer satisfaction perspective...
Last week Stephen Toub covered WithCancellation in a more thorough way than I did. You should read his article too!
I loved the original XCOM game (and terror from the deep was OK). Will definitely play this new game when it releases next week. They did something interesting for their recent trailer; an interactive trailer where you actually get to change how the flow goes.
This is a variant of WhenAllorError that a colleague asked me about. His scenario was that he had a lot of tasks to complete but since they all involved making HTTP requests to other servers he did not want to start them all at once but rather start a few and then as they completed start a few more. That's how I came up with WhenAllOrErrorBatched. The idea is that instead of giving it a list of tasks you provide a batchSize (number of parallel tasks) and a function that returns new tasks that will be called until it returns null.
1: public async static Task<T> WhenAllOrErrorBatched<T>(
2: int batchSize, Func<Task<T>> nextTask)
4: var result = new List<T>(batchSize);
5: var pending = new List<Task<T>>(batchSize);
6: bool pendingTasks = true;
7: while (true)
9: while (pendingTasks && pending.Count < batchSize)
11: var task = nextTask();
12: if (task == null)
14: pendingTasks = false;
21: if (pending.Count == 0)
26: await Task.WhenAny(pending);
28: for (int i = 0; i < pending.Count; i++)
30: if (pending[i].IsCompleted)
39: return result.ToArray();
Some researchers from MSR have published a paper on how do software engineers understand code changes. To me there are no surprises, especially since I participated in the survey the paper is based on (I think I'm quoted too actually). The bottom line is that developers spend a lot of time trying to understand previous code changes and that good check-in descriptions help in the effort to understand old changes.