Tech in the 603, The Granite State Hacker

Unloading the UI Thread in C# on Windows 10 + UWP

First I want to thank Matthew Groves for hosting the 1st known C# Advent (English).  I was honored to be able to grab the spot for Friday, December 22, 2017, which, happily, is the start of my Christmas holiday week, as well.

The crux of this post is that most visible performance issues in a Windows application come from the presentation layer.  Specifically, anything that puts load or wait states on the main “UI Thread” will make the app/application appear to hang or become unresponsive for periods of time. This post talks about strategies for getting load off the UI as much as possible, beyond the async/await mechanism in C#.  Most such load can be unloaded to a worker thread fairly easily.  Other tasks can be awaited together. In some cases, a UI component is involved, and it becomes necessary to manage load that, for that reason, reason MUST stay on the UI thread.

I remember when I was a kid hearing of projects for stock traders that handled hundreds of data update events every second and being totally intimidated by the thought of it.  I knew I’d “come of age” in technology when, in 2017, I worked with a focused team (known as “Blockheads”) to build such an app.  This latest generation “stock blotter” ran stable, without memory leakage, and with no apparent lag at tens of Gigabytes per second! These general ideas stem back to the project I worked on in 2016-2017 with BlueMetal for Fidelity Investments’ Equity Trading team, called Artis OMT.  Artis OMT has been on Fidelity’s Equity Trading floor for over a year now, and will soon reach a year of full deployment.  While Artis OMT was WPF, this post looks at similar performance ideas in a similar but different platform:  Windows 10 UWP (store apps).

Artis OMT didn’t start out able to handle 90Gigabytes of incoming data.  We had to use JetBrains tools to identify code that was bogging down or hanging the main UI thread.   That analysis, alone, is perhaps the subject of a different post, or more, some day.

When folks start thinking about UI Thread execution, the first thing most think of is Dispatcher.BeginInvoke().  This method is how you add workload to the UI thread.  I’m trying to talk about how to UNLOAD the UI thread, and/or manage your load so that the user won’t observe UI freezes or lockups.

Here, however, are a few relatively easy ways to really make use of the extra cores in your CPU, and make your apps appear to perform much better:


Task.Run(() => { … });

Classic depiction of processes running in sequence vs in parallel


The title of this says it all, really.  Push a workload off the current thread.  Use whenever you have long running processes that you don’t have to touch UI controls from.   If you have timing dependencies, you can manage them with Task.When, Task,Wait, or even better, Task.ContinueWith().  Examples below cover this a little more.



Batch remote service calls using Tasks and WhenAll()

Service calls are low hanging fruit.  So often I see code that makes calls in series, waiting on the results of one before making the next call, even though the two calls have no dependencies on each other…  it’s just so much easier to write the sequence case that folks let it hang.   await Task.WhenAll(…) is not as syntactically sweet, but still MUCH sweeter than having to set up an aggregate event.

///

/// Does one request at a time, holding up the entire process
/// at each step until it completes. Simpler code but….
/// Total time spent is the sum of all tasks’ time.
///
public async void GetContentinSequence(Session session)
{
    var dbContent = awaitGetDatabaseContent(session);
    var webContent = await GetWebContent(session);
    var userProfile = await GetUserProfile(session);
    var userContext = await GetUserContext(session);
}


///

/// Executes all requests simultaneously, letting the default task dispatcher do its thing.
/// total time spent is no more than the longest running individual task, all other things being equal.
///
public async void GetContentinParallel(Session session)
{
    var contextTask = GetDatabaseContent(session);
    var webContentTask = GetWebContent(session);
    var userProfileTask = GetUserProfile(session);
    var userContextTask = GetUserProfile(session);
    var stuff = new Task[] { contextTask, webContentTask, userProfileTask, userContextTask };
    await Task.WhenAll(stuff);
    var dbContent = contextTask.Result;
    var webContent = webContentTask.Result;
    var userProfile = userProfileTask.Result;
    var userContext = userContextTask.Result;
}

Here’s an example that makes this more clear:

var start = DateTimeOffset.Now;

var task1 = Task.Run(async () => { awaitTask.Delay(1000); });
var task2 = Task.Run(async () => { awaitTask.Delay(1500); }); //1.5 seconds
var task3 = Task.Run(async () => { await Task.Delay(1000); });
var task4 = Task.Run(async () => { awaitTask.Delay(1000); });
var tasks = new Task[] { task1, task2, task3, task4 };
Task.WhenAll(tasks).ContinueWith(t => { Debug.WriteLine(DateTimeOffset.Now – start); });



outputs something like:
00:00:01.5623681

As always, there’s some overhead with task switching.  You’ll notice that the time was just a few ticks longer than 1.5 seconds.

What if you can’t unload the UI thread?  what if your long running process must interact with controls like a huge grid that needs to calculate an aggregation of a data set that lives in it?   
Here’s an option…


DoEvents() erhhh… ummm…  await Task.Delay(…)

I once scrubbed references to Visual Basic from my CV and landed a job that had scrubbed VB from the job description.  I didn’t want to work for a company that would hire a “VB-Weenie” and they didn’t want to hire a “VB-Weenie”, either… but there was VB6 work to do. 

One thing that VB6 had going for it was a concept called DoEvents().   It enabled you to give up processing the current method to allow any pending events to execute. It would then return to finish the calling method.

In C#, the closest equivalent, nowadays, is “await Task.Yield()” or await.Task.Delay(…).

Most folks talk about using “await Task.Yield()” at the start of an awaitable method to make sure the whole method runs asynchronously.  There’s some sense to that.   More importantly, one can interrupt long running processes that must run on the UI in order to allow the UI to respond to user inputs.  In testing, I’ve seen that Task.Yield() often doesn’t allow enough room for redraws of the UI.  Likewise, setting a Task.Delay of a 1 tick timespan isn’t enough, either.  1 millisecond delay, however, does seem to suffice in my basic testing.

private async void LongRunningAggregatorOnUIThread(object sender, object e)

{

    await Task.Yield();
    timer.Stop();
    var timeoutRate = TimeSpan.FromMilliseconds(100);

    
    var timeout = DateTimeOffset.Now.Add(timeoutRate);
    var value = 0L;
    while (true)
    {
        value++;
        if (DateTimeOffset.Now >= timeout)
        {
            textbox.Text = value.ToString();
            await Task.Delay(1);
            timeout = DateTimeOffset.Now.Add(timeoutRate);
        }
    };
}



As always, use this very carefully.  This has overhead of its own, as well, that can cause performance issues…. including potential deadlocks.

Tech in the 603, The Granite State Hacker

UWP Equivalent for HttpUtility.ParseQueryString

Getting ready for my LUIS presentation at the Granite State Windows 10 Platform Devs Users Group (@WPDevNH), it made sense to demo LUIS using UWP rather than .NET classic.  (Join us, 11/16 at the Microsoft Store in Salem, NH…  https://www.meetup.com/Granite-State-NH-WPDev/events/243099117/ )

For a demo related to LUIS querying, I needed an alternative to System.Web.HttpUtility.ParseQueryString.  (based on this demo:  https://docs.microsoft.com/en-us/azure/cognitive-services/LUIS/luis-get-started-cs-get-intent )

I did a simple decorator of a Dictionary, adding a constructor to parse using WwwFormUrlDecoder, and overriding the ToString() to put it back together…

I whipped one up relatively quickly, but decided this would be a decent quick post.  Here’s my alt code:

usingSystem.Collections;
usingSystem.Collections.Generic;
using System.Net;
using System.Text;
usingWindows.Foundation;
namespaceLUIS_Examples
{
    public class ParseQueryString : IDictionary<string, string>
    {
        private IDictionary<string, string> _internalDictionary = new Dictionary<string, string>();
        public ParseQueryString(string queryString) :
            base()
        {
            var decoder = new WwwFormUrlDecoder(queryString);
            foreach (var item in decoder)
            {
                _internalDictionary.Add(item.Name, item.Value);
            }
        }
        public override string ToString()
        {
            var sb = new StringBuilder();
            foreach (var aPair in _internalDictionary)
            {
                sb.AppendFormat(“{0}={1}”, WebUtility.UrlEncode(aPair.Key), WebUtility.UrlEncode(aPair.Value));
            }
            return sb.ToString();
        }
        public string this[string key] { get => _internalDictionary[key]; set { _internalDictionary[key] = value; } }
        public ICollection<string> Keys => _internalDictionary.Keys;
        public ICollection<string> Values => _internalDictionary.Values;
        public int Count => _internalDictionary.Count;
        public bool IsReadOnly => _internalDictionary.IsReadOnly;
        public void Add(string key, string value)
        {
            _internalDictionary.Add(key, value);
        }
        public void Add(KeyValuePair<string, string> item)
        {
            _internalDictionary.Add(item);
        }
        public void Clear()
        {
            _internalDictionary.Clear();
        }
        public bool Contains(KeyValuePair<string, string> item)
        {
            return _internalDictionary.Contains(item);
        }
        public bool ContainsKey(string key)
        {
            return _internalDictionary.ContainsKey(key);
        }
        public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
        {
            _internalDictionary.CopyTo(array, arrayIndex);
        }
        public IEnumeratorstring, string>> GetEnumerator()
        {
            return _internalDictionary.GetEnumerator();
        }
        public bool Remove(string key)
        {
            return _internalDictionary.Remove(key);
        }
        public bool Remove(KeyValuePair<string, string> item)
        {
            return _internalDictionary.Remove(item);
        }
        public bool TryGetValue(string key, out string value)
        {
            return _internalDictionary.TryGetValue(key, out value);
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)_internalDictionary).GetEnumerator();
        }
    }
}

Tech in the 603, The Granite State Hacker

What’s New in C# 7 (CSharp)

Thanks again to folks who joined in for the presentation at the Granite State Windows Platform App Devs  (@WPDevNH) at the Microsoft Store in Salem, NH last night.

Meetup:
https://www.meetup.com/Granite-State-NH-WPDev/events/238684720/

The site most of the content came from was MSDN:



Here’s the slide deck:

and example code on GitHub:
https://github.com/GraniteStateHacker/WPDevNH_CSharp7

Tech in the 603, The Granite State Hacker

Intro to Rx.NET (Reactive Extensions)

Thanks to the gang for joining me at the Microsoft Store in Salem NH for my preso on “Intro to Rx.NET”   Being that it’s a toolkit I’ve been digging a lot at work lately, I had a feeling folks might appreciate a broad brush into to it.

Please check out the Granite State (NH) Windows Platform App Devs (#WPDevNH) on meetup.com to connect with the group and maybe even participate, yourself.  In addition to the core presentation topic, we had a great debate in speculation on how Microsoft’s purchase of Xamarin might settle out.  Also, I’ll be attending Build 2016, so we’re talking about having a special meeting early in April to recap and consider future presentations. (stay tuned!)

Rx reminds me a lot of other declarative language elements (XSL, XAML) in that it seems really natural, then you start looking at more advanced stuff and the complexity becomes boggling… then you start to really understand the abstractions and it feels natural again.

Without further ado, here’s my slides for the presentation:

I’d like to thank the folks at http://IntroToRx.com, I referenced them more than any other source putting this together.
Finally, for the code I demoed, please check out the post I mentioned, here:
Hope to see you soon!
-Jim Wilcox
The Granite State Hacker
Tech in the 603, The Granite State Hacker

Intro to Windows 10 Universal Devices and Raspberry Pi

I really enjoyed presenting “Intro to Windows 10 Universal with Raspberry Pi” to the Granite State Windows Platform App Devs (#WPDevNH) this past week. 

Here’s the slides which have a few decent links in them to get you started.

I will try to get a presentation on the next part of this sometime over the next couple months, with a dive in on the GPIO libraries.

Check out the group’s Meetup site for stuff going on going forward.

http://www.meetup.com/Granite-State-NH-WPDev/

Tech in the 603, The Granite State Hacker

Windows 10 and the Near Zero Hardware Liability Enterprise

With Windows 10, Microsoft is re-defining the BYOD (bring your own device) game, and it’s a subtly aggressive move that many will probably appreciate.

No, really.  Like you, I have heard “BYOD game-changer” shticks before, and dismissed it as marketing hype.  Hear me out.  (And also keep in mind that folks once often said “never” with respect to the cloud… but “never” is a lot longer than folks tend to look.)

Let me start by describing what I mean by “near zero hardware liability”.

There are already smaller organizations out there that have completely moved their hardware behind the wizard’s curtain. That is, they own little to no IT hardware themselves (with little to no capital expense, depreciation, or hardware liability.) These companies are typically small, use the cloud to support their infrastructure & services hardware, and BYOD for their employees’ desktop machines.

While cloud services are making serious headway into the enterprise, BYOD has been an arguably harder sell. The whole concept of BYOD has been largely dismissed by most larger companies because BYOD in in the Windows 7 (and prior) world can’t be managed.  Policy can’t be addressed and applied.  Data can’t be protected on an “unmanaged” employee owned device.  Hardware depreciation, liability, and support is kinda small compared to the other liabilities involved.

Imagine a more classically European view of the world however.  In Europe, a user’s computer traditionally is considered to be only a step away from personal property.  Like the days of being given a company car, the days of being issued a PC by your employer may well be coming to an end. 

At the Windows 10 Pre-flight Summit in Redmond this week (6/1-2), it seems the word of the day isn’t so much about “upgrade”.  It is, but there’s a bigger word floating around. 

It’s “provisioning”, or enrolling a device in an enterprise.

In Windows 10, the word “upgrade” is going to die.  It’s not just one platform for multiple devices.  It’s not just one platform for now, until Windows 11.  It’s one platform for the coming decades.  Upgrade to Windows 10, sure.  Update Windows 10, yes.  Upgrade from Windows 10, not in the works.  It’s also one very personal platform in more ways than one.

The day may be coming when part of a hiring decision (both by employee and employer) may be that an employee has devices of their own to bring to the table.  The employee will have their own support network, their own personal liability, and in order to accept the job, the employee must be willing to provision their devices with their employer.

Provisioning a device means the device gets an enterprise managed workspace, as us developers would say, a sandbox where all managed apps and app data live.  Provisioning also sets a minimum acceptable standard policy on the device.  If the device can’t meet the provisioning policy requirements, it won’t be accepted…  (sorry Charlie, you need new hardware.)

I speculate on how much effort it would save companies if they could have the security & policy management without the hardware ownership overhead, but I bet, all told, it would be pretty significant. 

In many ways it will be similar to the car analogy…  you can’t expect to keep a job if you can’t manage your own transportation sufficiently to get you there when you need to be there.

This is also a very aggressive tactic. Imagine an enterprise deciding to implement BYOD, and it’s very successful… to the point where you can’t really get a job at that company without bringing a Windows 10 device.  Is that a labor issue? 

By kicking down as many objections to BYOD as possible, Microsoft may even be looking to drive adoption from the bottom up. Rather than the CIO/CTO decreeing and pushing Windows 10 down, the BYOD user will use Windows 10’s features to overcome the BYOD objections.  Tired of the “golf cart” class standard issue machine at work, a power user brings in their own “hot rod”, and harasses IT until IT realizes the objections can be sufficiently mitigated with Windows 10… and the floodgates open.

I also speculate on the ramifications of the job market.  I could easily envision a day when the mark of a more desirable employee would be the higher end hardware they bring with them.  Imagine how it might re-invigorate the PC market if employee competition drove sales.  Imagine the PC becoming more important than the automobile in terms of employability-driving hardware, as a competitive attribute of an employee.  (The mark of a good chef is their knife set.  The mark of a solid information worker may be their laptop.)

It won’t hit all at once on July 29th.  It all has a ways to go.  It is a very thought provoking possibility.  What do you think? Is this on the path to Tomorrowland?

Edit 6/3:  Day 2 of the conference points out that Hyper-V 6.2 included in some editions of Windows 10 will enable virtualized Trusted Platform Module (v-TPM).  This means that an employer could provide a secure, Bitlocker enabled VM to an employee (which may or may not be provisioned), rather than provisioning the employee’s device as a directly provisioned system.   Yet another way to make BYOD a more Enterprise friendly policy.